SQL: Check if a row exists for each condition - sql

I'm not able to find a correct SQL query for my needs.
I have a table like this:
first_id | second_id | value
1 1 valueABC
1 2 valueLoL
2 1 valueBlaBla
2 2 valueLoL
Now I would like to select the first_ids where they have at least one row for EACH condition:
second_id = 1 and value = 'valueABC'
AND
second_id = 2 and value = 'valueLoL'
I already tried this, but the query is not correct:
select distinct first_id from myTable where (second_id = 1 and value = 'valueABC')
and (second_id = 2 and value = 'valueLoL') group by first_id having count(first_id) = 2
So in my example, first_id = 1 should be selected, as we have a row for each condition.
Can you help me please ?
Thank you.

I think you can do something like the following:
select first_id
from t
group by first_id
having
Max(case when second_id = 1 and value = 'valueABC' then 1 end) is not null and
Max(case when second_id = 2 and value = 'valueLoL' then 1 end) is not null;

Try this:
select first_id from
(select first_id,
sum(case when second_id = 1 and value = 'valueABC' then 1 else 0 end) as nbCond1,
sum(case when second_id = 2 and value = 'valueLoL' then 1 else 0 end) as nbCond2
from myTable
group by first_id) t
where nbCond1 > 0 and nbCond2 > 0;
Basically grouping by first_id and counting how many times the two conditions appear in a row for each first_id, then only selecting first_ids that have the number of occurences of both conditions > 0.
Fiddle

Related

SQL to find IDs which never had a column value

Below is my data:
ID
request_type
1
3
1
2
1
1
1
4
1
5
2
3
2
2
3
4
3
2
I need a query to fetch IDs that never had a request type of 1 (e.g. 2,3 from the previous table).
With conditional aggregation:
select id
from tablename
group by id
having count(case when request_type = 1 then 1 end) = 0
SELECT DISTINCT `ID`
FROM `my_table`
WHERE `ID` NOT IN (
SELECT DISTINCT `ID`
FROM `my_table`
WHERE `request_type` = 1
)
If 1 is the lowest possible value:
select ID
from tab
group by ID
having min (request_type) > 1
Or more generic:
select ID
from tab
group by ID
having max(case when request_type = 1 then 1 else 0 end) = 0

How to query within the same table

I need to query a single table based on the contents of the same table
currently i have used in within and, which is taking a lot of time to query & i know its not the smartest way
PID CID Status
1 1 1
1 2 0
1 3 1
1 4 1
1 5 1
2 1 1
2 2 1
2 3 1
2 4 0
2 5 0
from the above table i need results which satisfy the following combination
Select PID from Tablename where
(CID in (1) AND status 1)
AND
(CID in (2,3) AND status = 1)
AND
(CID in (4) AND status = 1)
AND
(CID in (5) AND status = 1)
So as per above requirement, i should get only PID 1
This should get all the PIDs which exist in all the select statements:
SELECT PID FROM TableName WHERE CID = 1 AND Status = 1
INTERSECT
SELECT PID FROM TableName WHERE CID IN (2, 3) AND Status = 1
INTERSECT
SELECT PID FROM TableName WHERE CID = 4 AND Status = 1
INTERSECT
SELECT PID FROM TableName WHERE CID = 5 AND Status = 1
You seem to want:
Select PID
from Tablename
where status = 1
group by PID
having sum(case when CID in (1) then 1 else 0 end) > 0 and
sum(case when CID in (2, 3) then 1 else 0 end) > 0 and
sum(case when CID in (4) then 1 else 0 end) > 0 and
sum(case when CID in (5) then 1 else 0 end) > 0;
Your query only tests values within a single row. The where condition can never evaluate to true.
Here is a db<>fiddle, showing that this returns PID = 1 for the data in your example.

SQL - not equal to operator is ignoring the rest of the where clause

product_id |value
1 | a
1 | b
1 | c
2 | a
2 | c
2 | d
3 | a
3 | c
3 | d
Below is my code, what I am trying to achieve with it is to check which product_id's have both 'a' and 'c' -that part works fine.
My problem is that when i do the following:
AND value != ('b')
It completely ignores the not equal to operator and still returns b...
SELECT
product_id, value
FROM
table
WHERE
value = 'a'
OR value = 'c'
AND value != ('b')
GROUP BY product_id
HAVING count(value) = 2
order by product_id
I guess my question is how do I fix it and why is this happening? thank you very much for your time. :)
EDIT:
What I should achieve is :
product_id value
2 a
3 a
Add proper parenthesis to the where clause. Now the And operator is applied between value='C' and value<>'b'
SELECT
product_id, value
FROM
table
WHERE
(value = 'a'
OR value = 'c')
AND value != ('b')
GROUP BY product_id
HAVING count(value) = 2
order by product_id
Update : : looks like fixing parenthesis will not fix your problem. Use conditional count in having clause to filter the groups.
SELECT product_id,
min(value) value
FROM table
GROUP BY product_id
HAVING Count(CASE WHEN value = 'a' THEN 1 END) = 1
AND Count(CASE WHEN value = 'c' THEN 1 END) = 1
AND Sum(CASE WHEN value <> 'b' THEN 0 ELSE 1 END) = 0
Order of operations.
value = 'a' OR value = 'c' AND value <> ('b')
will evaluate the same as
value = 'a' OR (value = 'c' AND value <> ('b'))
Change your conditional (WHERE) clause to
(value = 'a' OR value = 'c') AND value <> ('b')

To retrieve records having only two specific values

Have the following Data in the table
Example Table
ID Value
1 a
1 b
1 c
2 a
2 b
2 c
3 a
3 b
I need to retrieve records having ID with only two values a and b.
So i am expecting only the Record with ID 3 .
Can anyone help me with the query
I guess you could do something like
select
ID,
sum(case when value = 'a' then 1
when value = 'b' then 1
else 3 end)
from
table1
group by id
having
sum (case when value = 'a' then 1
when value = 'b' then 1
else 3 end) =2
SQL Fiddle
That will work:
select x.id from
(
select id from mytable where value = 'a'
union all
select id from mytable where value = 'b'
) x
group by x.id
having COUNT(*) = 2
and not exists (select * from mytable t where t.id = x.id and value <> 'a' and value <> 'b')

How to best use SQL to find common IDs that match multiple WHERE clauses

So I'm just starting to learn SQL, and hit upon the following problem. Suppose I have a table with 3 columns like so:
ID | Property_Name | Property_Value
1 | Color | "Blue"
1 | Size | "Large"
2 | Color | "Red"
3 | Color | "Orange"
3 | Size | "Small"
4 | Color | "Blue"
4 | Size | "Large"
...
Now, suppose I want to find the IDs that have Color=Blue and Size=Large (aka. ID 1 and 4),
how would I best do this. The best way I came up with is the following, but it seems clunky...
SELECT ID FROM PropertyTable
WHERE
ID IN (
SELECT ID FROM PropertyTable WHERE
Property_Name='Color' AND Property_Value='blue' )
AND
(Property_Name='Size' AND Property_Value='Large')
Thank you :)
EDIT: Forgot to add preformat tags to the example table text. Just did so.
How about self join?
SELECT T1.ID
FROM PropertyTable T1
JOIN PropertyTable T2 ON T1.ID = T2.ID
WHERE
T1.PropertyName = 'Color' AND T1.PropertyValue = 'Blue'
AND
T2.PropertyName = 'Size' AND T2.PropertyValue = 'Large'
Here is an SQLFiddle
If the values for Color and Size don't overlap, then you can do something like this.
SELECT
ID
FROM PropertyTable
WHERE Property_Name IN ('Color','Size')
AND Property_Value IN ('Blue','Large')
GROUP BY
ID
HAVING
COUNT(ID) = 2
If they do overlap then try this.
SELECT
ID
FROM PropertyTable
WHERE (Property_Name = 'Color' AND Property_Value = 'Blue')
OR (Property_Name = 'Size' AND Property_Value = 'Large')
GROUP BY
ID
HAVING
COUNT(ID) = 2
This is an example of a "set-within-sets" subquery. I think the most general approach is to use aggregation with a having clause:
select ID
from PropertyTable pt
group by ID
having sum(case when Property_Name='Color' AND Property_Value='blue' then 1 else 0 end) > 0 and
sum(case when Property_Name='Size' AND Property_Value='Large' then 1 else 0 end) > 0;
Each clause of the having statement is counting the number of rows that match each condition.
The reason I like this is because it is quite general If you wanted to add in another property, you just add similar clauses:
select ID
from PropertyTable pt
group by ID
having sum(case when Property_Name='Color' AND Property_Value='blue' then 1 else 0 end) > 0 and
sum(case when Property_Name='Size' AND Property_Value='Large' then 1 else 0 end) > 0 and
sum(case when Property_Name = 'Heating' and Property_Value = 'Gas' then 1 else 0 end) > 0;
If you wanted any of the three conditions, then you would use or:
select ID
from PropertyTable pt
group by ID
having sum(case when Property_Name='Color' AND Property_Value='blue' then 1 else 0 end) > 0 or
sum(case when Property_Name='Size' AND Property_Value='Large' then 1 else 0 end) > 0 or
sum(case when Property_Name = 'Heating' and Property_Value = 'Gas' then 1 else 0 end) > 0;