Выбор против подмножеств списка в MySQL - PullRequest
8 голосов
/ 15 февраля 2010

Я довольно новичок, и у меня есть две таблицы: "продукт" и "атрибуты продукта".

Вот некоторые воображаемые данные (фактические данные включают в себя больше таблиц)

Таблица продуктов:

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

Таблица атрибутов продукта:

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

Где каждый продукт имеет более одного возможного атрибута. У меня есть список идентификаторов атрибутов, таких как (21,10,25), и мне нужно выбрать все продукты, атрибуты которых являются подмножеством этого списка.

Возможно ли сделать это одним запросом?

Когда я фильтрую для (21,24), желаемый результат должен возвращать только продукт 11 (bbb)

Когда я фильтрую для (21,23,24), желаемым выходом является возврат продуктов 10 и 11.

Когда я фильтрую по (21), желаемый результат не должен возвращать ничего (поскольку все продукты имеют хотя бы один другой атрибут).

Ответы [ 7 ]

5 голосов
/ 15 февраля 2010

Если вы делаете вид, что ваш фильтр находится в таблице:

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))

Если он был в построенном запросе:

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>))

Это не в моей голове, такможет иметь опечатки.

1 голос
/ 15 февраля 2010

Пока MySQL не поддерживает комбинацию запросов EXCEPT,

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

Если вы хотите иметь только продукты со всеми заданными атрибутами, добавьте предложение HAVING COUNT(*)=n к первому внешнему запросу, где 'n' - длина списка атрибутов.

1 голос
/ 15 февраля 2010

Это должно вернуть только те идентификаторы, где все атрибуты для каждого идентификатора полностью содержатся в списке:

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
1 голос
/ 15 февраля 2010
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;
1 голос
/ 15 февраля 2010

Предполагается, что ваша таблица продуктов называется Product, а столбец ID в этой таблице просто называется Id:

SELECT * from Product p where p.Id IN 
  (Select id_product from ProductAttributes where id_attribute in (21, 23, 24))
0 голосов
/ 15 февраля 2010

Основываясь на ваших взглядах, ребята, я оптимизировал его еще больше и использовал только 1 утверждение COUNT, например:

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

Это работает? :)

Edit:
Этот код не возвращает название продукта или другие поля, которые у него могут быть. Это правильный:

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 голосов
/ 15 февраля 2010

позвольте мне публиковать простые мнимые данные (фактические данные включают в себя больше таблиц)

стол продукты

product_id | product_name                  
10          |   aaa                           
11     |    bbb  

таблица атрибут_продукта

attribute_id | product_id  <br>
21     |    10         
23     |    10         
24     |    10         
21     |    11         
24     |    11 

Я хочу это:

  • когда я фильтрую для (21,24), возвращается только продукт 11 (bbb)
  • при фильтрации по (21,23,24) возвращаются оба продукта
  • когда я фильтрую только для (21), который не возвращается ни один (потому что ни один продукт не имеет только этот атрибут)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...