Reputation: 41
I have 3 tables (scenes, categories, scenes_categories ) in a many to many relationship.
scenes ( id, title, description ) categories ( id, title ) scenes_categories ( scene_id, category_id )
I'm having problems making a query to select scenes that must match multiple categories. For example, I might want to select scenes that match category 3 AND category 5 AND category 8, but I can't figure out how to get this to work.
So far I've got something like
SELECT scenes.id, scenes.title, scenes.description
FROM scenes
LEFT JOIN scenes_categories ON scenes.id = scenes_categories.scene_id
LEFT JOIN categories ON scenes_categories.category_id = categories.id
WHERE scenes_categories.category_id = '3'
AND scenes_categories.category_id = '5'
AND scenes_categories.category_id = '8'
AND scenes.id = '1'
How can I select for records that must match all the category ID's specified?
Upvotes: 0
Views: 1402
Reputation: 146597
You need to require that a row exists in your many-to-many table for that sceneId, for each categoryId you are requiring: So try this:
SELECT s.id, s.title, s.description
FROM scenes s
WHERE s.id = '1'
And Exists (Select * From scenes_categories
Where scene_id = s.Id
And category_id = '3')
And Exists (Select * From scenes_categories
Where scene_id = s.Id
And category_id = '5')
And Exists (Select * From scenes_categories
Where scene_id = s.Id
And category_id = '8')
another option that should work is to do three inner joins instead:
SELECT s.id, s.title, s.description
FROM scenes s
Join scenes_categories c3
On c3.scene_id = s.Id
And c3.category_id ='3'
Join scenes_categories c5
On c5.scene_id = s.Id
And c5.category_id ='5'
Join scenes_categories c8
On c8.scene_id = s.Id
And c8.category_id ='8'
WHERE s.id = '1'
Upvotes: 4
Reputation: 60549
Charles Bretana's answer will work, but might want to check the performance of that against this to see which works better for you.
SELECT * FROM scenes
INNER JOIN (
SELECT scene_id
FROM scenes_categories
WHERE category_id IN (3,5,8)
GROUP BY scene_id
HAVING count(*) = 3
) valid ON scenes.id = valid.scene_id
Assuming your SQL is dynamic, this will probably be a bit easier to implement.
Upvotes: 3