SQL Oracle - Want to add another "like" condition to a case - sql

I have the following query:
Select
Count(Distinct Case When Play.Uuid Like ('i~%') Then Tap.Player_Id End) As Tapjoy_Ios
From
Player_Tapjoy Tap
Inner Join
Player Play
On
Tap.Player_Id = Play.Player_Id
Where
Trunc(Tap.Create_Dtime) >= To_Date('2012-Jan-01','yyyy-mon-dd')
I want to add another like constrain so that the result comes out where play.uuid like ('i~%' or 'ti~%')..but that doesn't seem to work. How could I implement this?

You need two full LIKE clauses connected by a logical OR, each having both the left and right sides of the LIKE keyword (column on the left, string value on the right).
count(Distinct Case When (Play.Uuid Like 'i~%') OR (Play.Uuid LIKE 'ti~%') Then Tap.Player_Id End) As Tapjoy_Ios
You could also do this with a single REGEXP_LIKE, using the regular expressiong ^t?i~.+:
count(Distinct Case When REGEXP_LIKE(Play.Uuid, '^t?i~.+') Then Tap.Player_Id End) As Tapjoy_Ios
^ is the start of the string
t? is an optional t
i~ is literal
.+ is any remaining characters, equivalent to % in a regular LIKE.

You can just use an OR:
Select Count(Distinct Case When Play.Uuid Like ('i~%')
OR Play.Uuid Like ('ti~%')
Then Tap.Player_Id End) As Tapjoy_Ios
From Player_Tapjoy Tap
Inner Join Player Play
On Tap.Player_Id = Play.Player_Id
Where Trunc(Tap.Create_Dtime) >= To_Date('2012-Jan-01','yyyy-mon-dd')

While the answers are correct, you're applying the condition at the wrong level. You normally want to FILTER the data for better performance, although the LIKE clause here makes it less significant.
Select Count(Distinct Tap.Player_Id) As Tapjoy_Ios
From Player_Tapjoy Tap
Inner Join Player Play On Tap.Player_Id = Play.Player_Id
Where Tap.Create_Dtime >= To_Date('2012-Jan-01','yyyy-mon-dd')
And (Play.Uuid Like ('i~%') OR Play.Uuid Like ('ti~%'))
As written in the question, it was processing all rows and fizzing on the ones that don't match the LIKE pattern(s). You also don't want to run functions against columns, which doesn't allow indexes to be used - I have updated your date filter. You didn't really need the TRUNC.

Related

Join under condition in Oracle SQL SELECT statement

I'm trying to join two tables under a condition but I haven't been able to make it work. I've been searching and reading but couldn't find an answer for my case.
This is the basic idea of what I'm trying to achieve (what I wrote in lowercase is what I want to achieve in my own words, in case you wonder):
SELECT TABLE1.STR_FULLNAME, TABLE1.STR_MAILBIZ, TABLE2.STR_IP
FROM TABLE1
INNER JOIN TABLE2
if TABLE2.STR_MACHINEUSER contains 'TEXT\' then join like this:
ON TABLE1.STR_LOGIN = SELECT SUBSTR(STR_MACHINEUSER, 6) AS STR_MACHINEUSER FROM TABLE2 WHERE
STR_MACHINEUSER LIKE 'TEXT\%'
else join like this:
ON TABLE1.STR_LOGIN = TABLE2.STR_MACHINEUSER
ORDER BY TABLE2.DT_INSERT DESC;
The content of Table1.STR_LOGIN and that of Table2.STR_MACHINEUSER are in some cases exactly the same and in some cases a prefix needs to be removed in Table2.STR_MACHINEUSER ('TEXT\'). I've seen that conditions should be handled with the CASE expression. I have tried different ways, but I couldn't make it work for what I need. I'm thinking that I might need a complete different approach, but I don't see what...
Does someone have a suggestion? Thanks in advance!
Maybe this is what you want:
SELECT TABLE1.STR_FULLNAME, TABLE1.STR_MAILBIZ, TABLE2.STR_IP
FROM TABLE1
INNER JOIN TABLE2 ON
(not TABLE2.STR_MACHINEUSER LIKE 'TEXT\%' and TABLE1.STR_LOGIN = TABLE2.STR_MACHINEUSER)
or
(TABLE2.STR_MACHINEUSER LIKE 'TEXT\%' and TABLE1.STR_LOGIN = SUBSTR(TABLE2.STR_MACHINEUSER, 6))
Sure you could shorten your statement using some case construct like:
case
when TABLE2.STR_MACHINEUSER LIKE 'TEXT\%'
then SUBSTR(TABLE2.STR_MACHINEUSER, 6) else TABLE2.STR_MACHINEUSER
end
and compare this to TABLE1.STR_LOGIN but I find (IMHO) the first (logic) join better readable.

how to select a row if multiple values are in a related table

I am trying to make a filter to find all the stuffs made of various substances.
In the database, there is:
a stuffs table
a substances table
a stuffs_substances join table.
Now, I want to find only all the stuffs that are made of gold AND silver (not all the stuffs that contain gold and all stuffs that contain silver).
One last thing: the end user can type only a part of the substance name in the filter form field. For example he will type silv and it will show up all the stuffs made of silver.
So I made this query (not working):
select "stuffs".*
from "stuffs"
inner join "stuffs_substances" as "substances_join"
on "substances_join"."stuff_id" = "stuffs"."id"
inner join "substances"
on "substances_join"."substance_id" = "substances"."id"
where ("substances"."name" like '%silv%')
and ("substances"."name" like '%gold%')
It returns an empty array. What am I doing wrong here?
Basically, you just want aggregation:
select st.*
from "stuffs" st join
"stuffs_substances" ss join
on ss."stuff_id" = st."id" join
"substances" s
on ss."substance_id" = s."id"
where s."name" like '%silv%' or
s."name" like '%gold%'
group by st.id
having count(*) filter (where s."name" like '%silv%') > 0 and
count(*) filter (where s."name" like '%gold%') > 0;
Note that this works, assuming that stuff.id is the primary key in stuffs.
I don't understand your fascination with double quotes and long table aliases. To me, those things just make the query harder to write and to read.
if you want to do search by part of word then do action to re-run query each time user write a letter of word , and the filter part in query in case of oracle sql way
in case to search with start part only
where name like :what_user_write || '%'
or in case any part of word
where name like '%' || :what_user_write || '%'
you can also use CAB, to be sure user can search by capital or small whatever
ok, you ask about join, I test this in mysql , it work find to get stuff made from gold and silver or silver and so on, hope this help
select sf.id, ss.code, sf.stuff_name from stuffs sf, stuffs_substances ss , substances s
where sf.id = ss.id
and s.code = ss.code
and s.sub_name like 'gol%'

Adding to complex DQL Query

Hello I have this query witch works fine
SELECT y,
CASE WHEN (v IS NULL) THEN 0 ELSE SUM(v.viewCount) END AS HIDDEN sumviewcount
FROM YTScraperBundle:YouTubeVideo y
LEFT JOIN y.allViews WITH v.firstFetch BETWEEN :fromDate AND :toDate
GROUP BY y ORDER BY sumviewcount DESC
This is the SQL that is generated by the DQL
SELECT y0_.id AS id0, y0_.video_id AS video_id1, y0_.name AS name2, y0_.type AS type3, y0_.link AS
link4, y0_.first_fetch AS first_fetch5, y0_.last_fetch AS last_fetch6, CASE WHEN (v1_.id IS NULL)
THEN 0 ELSE SUM(v1_.viewCount) END AS sclr7 FROM youtubevideo y0_ LEFT JOIN views v1_ ON y0_.id
v1_.youtubevideo_id AND (v1_.first_fetch BETWEEN ? AND ?) GROUP BY y0_.id, y0_.video_id, y0_.name,
y0_.type, y0_.link, y0_.first_fetch, y0_.last_fetch ORDER BY sclr7 DESC LIMIT 30 OFFSET 0
I need to add a upper LIKE clause, that sorts this first. The above query works fine, but it runs on all YouTubeVideo's y, if I want it to run on just some of the videos where name has a specifik LIKE value, I would add an AND clause after the LEFT JOIN.
But I dont know where to add it, if I add it after the:
BETWEEN :fromDate AND :toDate
Like this:
BETWEEN :fromDate AND :toDate AND y.name LIKE '%somevalue%'
The SQL renders like this:
LEFT JOIN views v1_ ON y0_.id
v1_.youtubevideo_id AND (v1_.first_fetch BETWEEN ? AND ? AND y.name LIKE '%somevalue%')
The clause I am adding should not be inside the between paranthesis. It shouldn't it be outside?
Anyway how can I get around the BETWEEN statment? can I make it a:
...MyComparison AND BETWEEN...
?
try below where clause
Where '2014-10-01'< Date_Column and '2014-11-01'>Date_column and name like '%abc%'

How do you explicitly show rows which have count(*) equal to 0

The query I'm running in DB2
select yrb_customer.name,
yrb_customer.city,
CASE count(*) WHEN 0 THEN 0 ELSE count(*) END as #UniClubs
from yrb_member, yrb_customer
where yrb_member.cid = yrb_customer.cid and yrb_member.club like '%Club%'
group by yrb_customer.name, yrb_customer.city order by count(*)
Shows me people which are part of clubs which has the word 'Club' in it, and it shows how many such clubs they are part of (#UniClubs) along with their name and City. However for students who are not part of such a club, I would still like for them to show up but just have 0 instead of them being hidden which is what's happening right now. I cannot get this functionality with count(*). Can somebody shed some light? I can explain further if the above is not clear enough.
I'm not familiar with DB2 so I'm taking a stab in the dark, but try this:
select yrb_customer.name,
yrb_customer.city,
CASE WHEN yrb_member.club like '%Club% THEN count(*) ELSE 0 END as #UniClubs
from yrb_member, yrb_customer
where yrb_member.cid = yrb_customer.cid
group by yrb_customer.name, yrb_customer.city order by count(*)
Basically you don't want to filter for %Club% in your WHERE clause because you want ALL rows to come back.
You're going to want a LEFT JOIN:
SELECT yrb_customer.name, yrb_customer.city,
COUNT(yrb_member.club) as clubCount
FROM yrb_customer
LEFT JOIN yrb_member
ON yrb_member.cid = yrb_customer.cid
AND yrb_member.club LIKE '%Club%
GROUP BY yrb_customer.name, yrb_customer.city
ORDER BY clubCount
Also, if the tuple (yrb_customer.name, yrb_customer.city) is unique (or is supposed to be - are you counting all students with the same name as the same person?), you might get better performance out of the following:
SELECT yrb_customer.name, yrb_customer.city,
COALESCE(club.count, 0)
FROM yrb_customer
LEFT JOIN (SELECT cid, COUNT(*) as count
FROM yrb_member
WHERE club LIKE '%Club%
GROUP BY cid) club
ON club.cid = yrb_customer.cid
ORDER BY club.count
The reason that your original results were being hidden was because in your original query, you have an implicit inner join, which of course requires matching rows. The implicit-join syntax (comma-separated FROM clause) is great for inner (regular) joins, but is terrible for left-joins, which is what you really needed. The use of the implicit-join syntax (and certain types of related filtering in the WHERE clause) is considered deprecated.

MySQL to PostgreSQL: GROUP BY issues

So I decided to try out PostgreSQL instead of MySQL but I am having some slight conversion problems. This was a query of mine that samples data from four tables and spit them out all in on result.
I am at a loss of how to convey this in PostgreSQL and specifically in Django but I am leaving that for another quesiton so bonus points if you can Django-fy it but no worries if you just pure SQL it.
SELECT links.id, links.created, links.url, links.title, user.username, category.title, SUM(votes.karma_delta) AS karma, SUM(IF(votes.user_id = 1, votes.karma_delta, 0)) AS user_vote
FROM links
LEFT OUTER JOIN `users` `user` ON (`links`.`user_id`=`user`.`id`)
LEFT OUTER JOIN `categories` `category` ON (`links`.`category_id`=`category`.`id`)
LEFT OUTER JOIN `votes` `votes` ON (`votes`.`link_id`=`links`.`id`)
WHERE (links.id = votes.link_id)
GROUP BY votes.link_id
ORDER BY (SUM(votes.karma_delta) - 1) / POW((TIMESTAMPDIFF(HOUR, links.created, NOW()) + 2), 1.5) DESC
LIMIT 20
The IF in the select was where my first troubles began. Seems it's an IF true/false THEN stuff ELSE other stuff END IF yet I can't get the syntax right. I tried to use Navicat's SQL builder but it constantly wanted me to place everything I had selected into the GROUP BY and that I think it all kinds of wrong.
What I am looking for in summary is to make this MySQL query work in PostreSQL. Thank you.
Current Progress
Just want to thank everybody for their help. This is what I have so far:
SELECT links_link.id, links_link.created, links_link.url, links_link.title, links_category.title, SUM(links_vote.karma_delta) AS karma, SUM(CASE WHEN links_vote.user_id = 1 THEN links_vote.karma_delta ELSE 0 END) AS user_vote
FROM links_link
LEFT OUTER JOIN auth_user ON (links_link.user_id = auth_user.id)
LEFT OUTER JOIN links_category ON (links_link.category_id = links_category.id)
LEFT OUTER JOIN links_vote ON (links_vote.link_id = links_link.id)
WHERE (links_link.id = links_vote.link_id)
GROUP BY links_link.id, links_link.created, links_link.url, links_link.title, links_category.title
ORDER BY links_link.created DESC
LIMIT 20
I had to make some table name changes and I am still working on my ORDER BY so till then we're just gonna cop out. Thanks again!
Have a look at this link GROUP BY
When GROUP BY is present, it is not
valid for the SELECT list expressions
to refer to ungrouped columns except
within aggregate functions, since
there would be more than one possible
value to return for an ungrouped
column.
You need to include all the select columns in the group by that are not part of the aggregate functions.
A few things:
Drop the backticks
Use a CASE statement instead of IF() CASE WHEN votes.use_id = 1 THEN votes.karma_delta ELSE 0 END
Change your timestampdiff to DATE_TRUNC('hour', now()) - DATE_TRUNC('hour', links.created) (you will need to then count the number of hours in the resulting interval. It would be much easier to compare timestamps)
Fix your GROUP BY and ORDER BY
Try to replace the IF with a case;
SUM(CASE WHEN votes.user_id = 1 THEN votes.karma_delta ELSE 0 END)
You also have to explicitly name every column or calculated column you use in the GROUP BY clause.