How to query a join table so that multiple criteria are met? - mysql

I have a table with 2 columns (see below). A member can have multiple responses to a question:
RESPONSES
---------
member_id INT
response_id INT
SAMPLE DATA
member_id -- response_id
1 -- 3
1 -- 5
2 -- 1
2 -- 5
2 -- 9
3 -- 1
3 -- 5
3 -- 6
What I need to do is query the table for member that meet ALL response criteria. For example I need to select all members that have a response_id of 1 AND 5. I am using the following query:
SELECT DISTINCT member_id
FROM responses
WHERE response_id = 1 AND response_id = 5
I would expect to get back member_id's 2 and 3. However I am getting nothing returned. I used EXPLAIN and it shows there is an error in my where query. What am I doing wrong?
Also, is there a function similar to IN where all the criteria must be met in order to return true?

This should work:
SELECT member_ID
FROM responses
WHERE response_ID IN (1,5)
GROUP BY member_ID
HAVING COUNT(DISTINCT response_id) = 2
You need to count the number of records returned which is equal to the number of values supplied in your IN clause.
SQLFiddle Demo

Related

how use having count (distinict (col1, col2 )) >2 to get records fulfill any 2 or more conditions

How can I use HAVING COUNT (DISTINCT (col1, col2)) >2 in sql to find out those users who have any 3 following records or more
SELECT user_id FROM users_responses
WHERE
(question_id = 3 AND response_id = 6)
OR(question_id = 7 AND response_id = 18)
OR(question_id = 1 AND response_id = 5)
OR(question_id = 8 AND response_id = 22)
OR(question_id = 2 AND response_id = 3)
HAVING COUNT(DISTINCT question_id, response_id) > 2 ;
I have total 10 different users in this table with same and different responses. 3 users have exact responses are given above and 3 users fulfill 4 conditions while others users have only1-2 same responses given in query.
I need to fetch all those distinct user_id from this table who have responded to above question id and have same responses.
I tried but it gives only first record
Table structure
Id | user_id | question_id | response_id
Any idea how to make changes to get it work properly.

Count first occurence with column value ordered by another column

I have an assigns table with the following columns:
id - int
id_lead - int
id_source - int
date_assigned - int (this represents a unix timestamp)
Now, lets say I have the following data in this table:
id id_lead id_source date_assigned
1 20 5 1462544612
2 20 6 1462544624
3 22 6 1462544615
4 22 5 1462544626
5 22 7 1462544632
6 25 6 1462544614
7 25 8 1462544621
Now, lets say I want to get a count of the rows whose id_source is 6, and is the first entry for each lead (sorted by date_assigned asc).
So in this case, the count would = 2, because there are 2 leads (id_lead 22 and 25) whose first id_source is 6.
How would I write this query so that it is fast and would work fine as a subquery select? I was thinking something like this which doesn't work:
select count(*) from `assigns` where `id_source`=6 order by `date_assigned` asc limit 1
I have no idea how to write this query in an optimal way. Any help would be appreciated.
Pseudocode:
select rows
with a.id_source = 6
but only if
there do not exist any row
with same id_lead
and smaller date_assigned
Translate it to SQL
select * -- select rows
from assigns a
where a.id_source = 6 -- with a.id_source = 6
and not exists ( -- but only if there do not exist any row
select 1
from assigns a1
where a1.id_lead = a.id_lead -- with same id_lead
and a1.date_assigned < a.date_assigned -- and smaller date_assigned
)
Now replace select * with select count(*) and you'll get your result.
http://sqlfiddle.com/#!9/3dc0f5/7
Update:
The NOT-EXIST query can be rewritten to an excluding LEFT JOIN query:
select count(*)
from assigns a
left join assigns a1
on a1.id_lead = a.id_lead
and a1.date_assigned < a.date_assigned
where a.id_source = 6
and a1.id_lead is null
If you want to get the count for all values of id_source, the folowing query might be the fastest:
select a.id_source, count(1)
from (
select a1.id_lead, min(a1.date_assigned) date_assigned
from assigns a1
group by a1.id_lead
) a1
join assigns a
on a.id_lead = a1.id_lead
and a.date_assigned = a1.date_assigned
group by a.id_source
You still can replace group by a.id_source with where a.id_source = 6.
The queries need indexes on assigns(id_source) and assigns(id_lead, date_assigned).
Simple query for that would be
check here http://sqlfiddle.com/#!9/8666e0/7
select count(*) from
(select * from assigns group by id_lead )t
where t.id_source=6

common values b/w fields

This table lists user and item id's
user_id item_id
1 1
1 2
1 3
2 1
2 3
3 1
3 4
3 3
How can I run a query on this table to list all the items that are common between given users.
My guess is, this will need a self join, but I'm not sure.
i am trying this quering but it's returning an error
SELECT *
FROM recs 1
JOIN recs 2 ON 2.user_id='2' AND 2.item_id=1.item_id
WHERE 1.user_id='1'
Try using alias names that start in a letter:
SELECT *
FROM recs r1
JOIN recs r2 ON r2.user_id='2' AND r2.item_id=r1.item_id
WHERE r1.user_id='1'
This returns
user_id item_id
------- -------
1 1
1 3
for your data. Demo on sqlfiddle.
Note: I kept single quotes in the query, because I assume that both IDs in your table are of character type. If that is not the case, remove single quotes around user ID values '1' and '2'.
I want it for n number of users ... a I want the query to return all item_id's that are common among the users
SELECT DISTINCT(r1.item_id)
FROM recs r1
WHERE EXISTS (
SELECT *
FROM recs r2
WHERE r2.item_id=r1.item_id
AND r1.user_id <> r2.user_id
)
Demo #2.

MySQL case-when-then (or other ways) to check values of multiple rows

I request some help with MySQL when-then statement to fetch all the sid from the table after comparing multiple records having same sid but different cid-data values:
flag sid cid data
---- --- --- ----
1 300 1 john
1 300 2 john_email
1 300 3 77500
1 300 4 ok
1 301 1 jack
1 301 2 john_email
1 301 3 72210
1 301 4 notok
Here for each sid, I need to check if (sid=2 has data=john_email) AND (sid=4 has data=ok)
Only if both the conditions are satisfied, I return the sid. i.e. the output will be '300' only.
I am confused how to use the case-when-then and compare 'data' with 'john_email' and also compare data with 'ok' ... based on the cid values. Thanks for reading.
try
select sid
from your_table
group by sid
where (cid=2 and data='john_email')
or (cid=4 and data='ok')
having sum(cid=2)=1 and sum(data='john_email')=1
and sum(cid=4)=1 and sum(data='ok')=1
SQLFiddle example
You should join the table to itself, then you can check the condition in the two rows as if it was one row...
SELECT T1.sid
FROM MYTABLE T1
JOIN MYTABLE T2 ON T1.SID=T2.SID AND T1.CID=1 AND T2.CID=4
WHERE T1.DATA='john'
AND T2.DATA='ok'
Note that I used the CID values in the join clause, but you will have to adjust them if you want to join on different data rows...
What you can do is use a subquery and check if the value exists.
SELECT
*
FROM
table outertable
WHERE
( cid=2 AND data='john_email' )
AND
EXISTS ( SELECT sid FROM table WHERE cid = 4 AND data = 'ok' AND sid = outertable.sid )

Update last child id in parent table using mysql

Given the following tables:
Topic
id, last_updated_child_id
Response
id, topic_id, updated_at
How do I update the Topic table so the last_updated_child_id is equal to the latest response id (based on date).
So for example given:
Topic
id last_updated_child_id
-- -----------------------
1 null
2 null
3 null
Response
id topic_id updated_at
-- ---- ----
1 1 2010
2 1 2012
3 1 2011
4 2 2000
I would like to execute an UPDATE statement that would result in the Topic table being:
id last_updated_child_id
-- -----------------------
1 2
2 4
3 null
Note: I would like to avoid temp tables if possible and am happy for a MySQL specific solution.
Not very efficient, but relatively simple:
UPDATE topic
SET last_id = (SELECT id
FROM response
WHERE topic_id = topic.id
ORDER BY updated_at DESC
LIMIT 1);