Selecting against subsets of a list in MySQL

前端 未结 7 1881
谎友^
谎友^ 2021-01-12 07:21

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

相关标签:
7条回答
  • 2021-01-12 07:32

    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.

    0 讨论(0)
  • 2021-01-12 07:34

    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))
    
    0 讨论(0)
  • 2021-01-12 07:38

    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
    
    0 讨论(0)
  • 2021-01-12 07:43

    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
    
    0 讨论(0)
  • 2021-01-12 07:46

    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.

    0 讨论(0)
  • 2021-01-12 07:50
    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;
    
    0 讨论(0)
提交回复
热议问题