I think I found the answer to my question, I'm just unsure of the syntax, I keep getting SQL errors.
Basically, I want to do the opposite of IN. Take this example:
SELECT *
FROM users INNER JOIN
tags ON tags.user_id = users.id
WHERE tags.name IN ('tag1', 'tag2');
The above will return ANY users that have 'tag1' OR 'tag2'. I want users that have BOTH. They must have both tags to be returned. I'm assuming the keyword ALL should be used, but can't get it to work.
Thanks for your help.
Give this a try
Assuming that any given tag can only be present once per user.
Ok, stating the problem again.
"Find users that have entries in the tags table for both tag1 and tag2". This means at least 2 rows in the child tags table for each user table entry
Solution 1: The intersection of "users with tag1" and "users with tag2"
Solution 2: EXISTS
Solution 3: JOIN
Solution 4: IN
All The EXISTS, INTERSECT and IN should give the same execution plan in SQL Server
Now, these are all for the case where you are looking for 2 tags. As you want more tags, they become cumbersome so use shahkalpesh's solution.
However, I'd modify it so the tags are in a table and no extra OR clauses are needed
You'll need to check for the existence of two rows, rather than being able to do a simple
IN
(which will only check the values within each joined record). Maybe something like:What about
I would do exactly what you are doing first, because that gets a list of all users with 'tag1' and a list of all users with 'tag2', but in the same response obviously. So, we have to add some more:
Do a
group by users
(or users.id) and thenhaving count(*) == 2
. That will group duplicate users (which means those with both tag1 and tag2) and then the having-part will remove the ones with just one of the two tags.This solution avoids adding yet another join-statement, but honestly I'm not sure which is faster. People, feel free to comment on the performance-part :)
EDIT: Just to make it easier to try out, here's the whole thing: