Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selecting against subsets of a list in MySQL

Tags:

select

mysql

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 )

Products Table:

product_id | product_name                  
10         |   aaa                           
11         |   bbb   
12         |   ccc

Product Attributes Table:

attribute_id | product_id
      21     |    10         
      23     |    10         
      24     |    10         
      21     |    11         
      24     |    11         
      21     |    12         
      25     |    12         

Where each product has more than one possible attribute. I have a list of attribute ids like (21,10,25) and I need to select all products whose attributes are a subset of that list.

Is it possible to do this in one query?

When I filter for (21,24) desired output is to return only product 11 (bbb)

When I filter for (21,23,24) desired output is to return products 10 and 11.

When I filter for (21) desired output is to return none (because all products have at least one other attribute).

like image 863
Bogdan Ciulei Avatar asked Feb 15 '10 02:02

Bogdan Ciulei


4 Answers

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.

like image 106
Phil Wallach Avatar answered Nov 20 '22 05:11

Phil Wallach


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))
like image 29
Eric J. Avatar answered Nov 20 '22 06:11

Eric J.


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
like image 30
user273224 Avatar answered Nov 20 '22 05:11

user273224


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;
like image 31
Qwerty Avatar answered Nov 20 '22 04:11

Qwerty