I\'m quite a begginer and I have two tables: \"product\" and \"product attributes\".
Here\'s some imaginary data (the actual stuff involves more tables )
Pr
If you pretend that your filter is in a table:
select *
from product p
where not exists (
select 1
from attributes a
where a.product_id = p.product_id
and not exists(
select 1
from filter f
where f.id_attribute = a.id_attribute))
If it was in a constructed query:
select *
from product p
where not exists (
select 1
from attributes a
where a.product_id = p.product_id
and attribute_id not in (<list>))
This is off the top of my head, so may have typos.
Assuming your product table is called Product and the ID column in that table is just called Id:
SELECT * from Product p where p.Id IN
(Select id_product from ProductAttributes where id_attribute in (21, 23, 24))
This should return only those id's where all attributes for each id are completely contained within the list:
select attribute_match.id_product from
(select id_product, count(*) c from attributes
where id_attribute in (21, 10, 25)
group by id_product) attribute_match,
(select id_product, count(*) c_count from attributes
group by id_product) attribute_total
where attribute_match.id_product = attribute_total.id_product
and attribute_match.c = attribute_total.c
Based on your insight guys, I optimized it even further and used only 1 COUNT statement like this:
SELECT * ,COUNT(p.product_id) AS c FROM product_attribute pa
LEFT JOIN products p ON pa.product_id = p.product_id AND pa.attribute_id NOT IN ($filter_list)
GROUP BY pa.product_id
HAVING c=0
Does it work ? :)
Edit:
That code doesn't return the product's name or other fields it might have. This is the correct one:
SELECT * ,COUNT(pa.product_id ) AS c FROM products p
LEFT JOIN product_attribute pa ON pa.product_id = p.product_id AND pa.attribute_id NOT IN ($filter)
GROUP BY p.product_id
HAVING c=0
Until MySQL supports the EXCEPT
query combination,
SELECT product_id
FROM attributes
WHERE product_id NOT IN (
SELECT product_id
FROM attributes
WHERE attribute_id NOT IN (21, 23, 24)
)
GROUP BY product_id
UNION
SELECT id
FROM products AS p
LEFT JOIN attributes AS a
ON p.id = a.product_id
WHERE a.product_id IS NULL
If you wish to have only the products with all the given attributes, add a HAVING COUNT(*)=n
clause to the first outer query, where 'n' is the length of the attribute list.
select
P.id,
P.name,
count(P.id) as matched_attr_count,
count(PA.a_id) as total_attr_count
from
product_attributes PA
left join product P on P.id = PA.p_id and PA.a_id in (21,23,24)
group by
PA.p_id
having
matched_attr_count = total_attr_count;