2013-05-31 2 views
0

есть product стол и product_attributes стол. Я хочу, чтобы фильтр продуктов с необходимыми атрибутами, здесь мой SQL:Присоединиться к тому месту, где в состоянии затруднения

SELECT * FROM product p 
INNER JOIN product_attributes p2 ON p.id = p2.product_id 
WHERE p2.attribute_id IN (637, 638, 629)) 

Но это дает мне все продукты, даже если продукт имеет только один атрибут (637, например). Но мне нужны продукты со всеми атрибутами (637, 638, 629).

+1

Показаны примеры данных и ожидаемый результат, которые помогут нам помочь вам. – hims056

+0

Вы явно реализуете предложение WHERE для проверки наличия в таблице p2. Поэтому вы даже не пытаетесь ограничить финальную таблицу. Для этого вам нужен внешний SELECT и фильтр производной таблицы. – arkascha

ответ

1

Там в довольно стандартный подход:

select * from product 
where id in (
    SELECT id 
    FROM product p 
    JOIN product_attributes p2 ON p.id = p2.product_id 
     AND p2.attribute_id IN (637, 638, 629) 
    GROUP BY id 
    HAVING COUNT(distinct attribute_id) = 3) 

HAVING условие гарантирует, что было 3 различных идентификаторов атрибутов (то есть все они были найдены).

Это может быть выражено как прямое соединение (а не ID IN (...)), но его проще читать и выполнять ОК, как при этом.

Небольшой интерес может заключаться в перемещении условия идентификатора атрибута в состояние включения JOIN.

+0

Спасибо @Bohemian, пожалуйста, просмотрите мой комментарий при ответе выше – kirugan

+0

Есть ли причина использовать 'AND p2.attribute_id' вместо' WHERE p2.attribute_id'? – kirugan

+0

Оптимизированный обычно интерпретирует их как одно и то же, но сделать базу данных нет. В общем, включение его в условие соединения будет лучше (по крайней мере, хуже). – Bohemian

1

Это пример подзапроса «set-in-sets». Я хотел, чтобы решить их с агрегацией и п having, потому что это наиболее гибкое решение:

SELECT p.* 
FROM product p join 
    product_attributes pa 
    on p.id = pa.product_id 
group by p.id 
having sum(pa.attribute_id = 637) > 0 and 
     sum(pa.attribute_id = 638) > 0 and 
     sum(pa.attribute_id = 629) > 0 

Альтернативой having оговорка:

having count(distinct case when pa.attribute_id IN (637, 638, 629) 
          then pa.attribute_id 
         end) = 3 
0

Вы можете использовать запрос, как это:

SELECT * FROM product p 
INNER JOIN product_attributes p21 
     ON p.id = p21.product_id and p21.attribute_id = 637 
INNER JOIN product_attributes p22 
     ON p.id = p22.product_id and p22.attribute_id = 638 
INNER JOIN product_attributes p23 
     ON p.id = p23.product_id and p23.attribute_id = 629 
+0

Я думаю, что это плохой подход, а что, если пользователь хочет фильтровать по 50 атрибутам? :) – kirugan

+0

В этом случае вы должны использовать запрос из других ответов :) –

Смежные вопросы