Reputation: 1124
I'm not the sure the title is really helpful, so here is my problem, here are three tables :
cats :
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
+-------+--------------+------+-----+---------+----------------+
tags :
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
+-------+--------------+------+-----+---------+----------------+
cats_tags:
+--------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| id_cat | int(11) | NO | | NULL | |
| id_tag | int(11) | NO | | NULL | |
+--------+---------+------+-----+---------+----------------+
let's imagine that the tables are populated by 10 cats, and 5 tags (id 1 to 5) and that those cats are tagged with some random tags each.
how can I select all cats that have an entire list of tags ?
for example how can I list cats with tags 2 and 3 (it could be 1,2 and 3, or 2,3 and 4) but not cats who only have 2 or 3 or none of those two tags ?
I'm not sure it's standard sql, I'd want to do that with mysql.
EDIT:
I tried that :
select
c.id, c.name
from
cats c
inner join cats_tags r on c.id = r.id_cat
where
r.id_tag in (:tags)
group by c.id
unitl I remembered that in would take any cat that has at least of the :tags list I asked for. and I only want cats that has all the tags I gave.
Upvotes: 1
Views: 75
Reputation: 181104
You might approach the problem like this:
SELECT cat_id
FROM (
SELECT DISTINCT cat_id, tag_id
FROM cat_tags
WHERE tag_id IN (2,3)
) tag23
GROUP BY cat_id
HAVING COUNT(*) = 2
The inline view is required because nothing you have shown prevents the same (cat, tag) pairing from appearing multiple times in cat_tags
; the query could be expressed more simply if it could be assumed (because of a DB constraint) that such duplication would not occur.
You can join cat
to the result if you need to get cat names.
Upvotes: 2
Reputation: 7890
use where exists...subquery
:
select distinct c.*
from cat c
where exists
( select 1 from cats_tags ct
join tags t on ct.id_tag=t.id
where t.id=2 and c.id=ct.id_cat
)
and exists
( select 1 from cats_tags ct
join tags t on ct.id_tag=t.id
where t.id=3 and c.id=ct.id_cat
)
Upvotes: 0