поиск 2 вхождений в реляционной таблице в MySQL

У меня есть таблица, заполненная категориями, другая заполнена продуктами. Между ними у меня есть таблица категорий продуктов всего с 3 столбцами:

  • id
  • ид_категории
  • идантификационный номер продукта

отлично работает для поиска продуктов в определенной категории:

LEFT JOIN `products-categories` pc ON p.id = pc.product_id 

(p — это моя таблица продуктов.)

При поиске товаров в определенных категориях я просто использую:

WHERE pc.category_id IN (0,34,35,36,37,38,39,168)

но теперь, как я могу объединить пункты 2 категорий? Я хотел бы найти все продукты, представленные, скажем, в категориях 34 и 255.

Я не могу просто добавить «И ГДЕ», потому что это отношение будет в другой строке (для каждой результирующей строки есть только один идентификатор категории...

Пример:

product_id | category_id
1            22
1            34
1            47
2            34
2            65
2            255
2            313
3            22

Моя таблица продуктов просто выглядит «как-то так»:

id | name | price | ...
-----------------
1    fork   2.21
2    knife  3.55

Итак, что я пытаюсь сделать на простом английском языке:

Найти все продукты в категории 34, которые также отображаются в категории 255, это должно вернуть мне идентификатор продукта 2 (только один раз)

Делать это таким образом неправильно: (Это настоящий код)

SELECT DISTINCT `ref`,`spec_varc_titre_fr`,`price_sell`,`spec_bool_new`,`defaultmedia_id` 
FROM `productmanager_products` p 
LEFT JOIN `productmanager_products-categories` pc 
ON p.id = pc.product_id 
WHERE pc.category_id IN (0,34,35,36,37,38,39,168)
AND spec_varc_gender = 'F' 
AND pc.category_id IN (0,255) 
AND `price_sell` BETWEEN 1.27 
AND 38.83 
ORDER BY pc.ordering ASC 
LIMIT 0,15;

потому что 34 и 255 находятся в разных строках, даже если это один и тот же продукт...


person Vincent Duprez    schedule 24.05.2014    source источник
comment
так что, если продукты относятся к 34 И 255, а также какой-то другой val, должен ли этот вид продукта также учитываться?   -  person Abhik Chakraborty    schedule 24.05.2014
comment
да. пока есть хотя бы для product_id #1, 2 строки: 1-34 и 1-255   -  person Vincent Duprez    schedule 24.05.2014
comment
@AbhikChakraborty только что добавил пример, чтобы было понятнее   -  person Vincent Duprez    schedule 24.05.2014


Ответы (2)


Возможно, самый простой способ в MySQL — использовать group by и предложение having:

select pc.productId
from product_categories pc
where categoryId in (34, 255)
group by pc.productId
having count(*) = 2;

РЕДАКТИРОВАТЬ:

Если вы хотите проверить классы эквивалентности, вы можете использовать аналогичную идею в более общей форме:

select pc.productId
from product_categories pc
group by pc.productId
having sum(CategoryId in (34, 35, 36)) > 0 and
       sum(CategoryId in (254, 255, 256)) > 0;
person Gordon Linoff    schedule 24.05.2014
comment
но у меня есть 2 списка идентификаторов категорий, скажем: строка 34,35,36 и 254,255,256 должна возвращаться, если «присутствует» в обоих этих списках - person Vincent Duprez; 24.05.2014
comment
Что вы имеете в виду в обоих этих списках? Это означало бы, что у них есть идентификаторы 34, 35, 36, 254, 255 и 256 — та же идея, что и в этом ответе. - person Gordon Linoff; 24.05.2014
comment
Просто добавил реальный пример в мой исходный вопрос, чтобы сделать его немного яснее. - person Vincent Duprez; 24.05.2014
comment
@Винсент Дюпрез. . . В первом ответе должны быть продукты как в категориях 34, так и в 255 (мое последнее редактирование просто изменило номера категорий). - person Gordon Linoff; 24.05.2014
comment
Я получаю странные результаты и время запроса до 10 секунд... (ранее было 30 мс) - person Vincent Duprez; 24.05.2014

В конце концов, я использовал внутреннее соединение между двумя операторами select. похоже, это способ получить общие, одинаковые строки.

теоретический код:

select * from
  (select * from table) A
inner join
  (select * from table2) B
on A.id = B.id

необработанный код для архива:

SELECT SQL_CALC_FOUND_ROWS A.`id`,A.`ref`,A.`spec_varc_titre_fr`,A.`price_sell`,A.`spec_bool_new`,A.`defaultmedia_id` FROM
                    ( 
                            SELECT DISTINCT `id`,`ref`,`spec_varc_titre_fr`,`price_sell`,`spec_bool_new`,`defaultmedia_id`
                            FROM `productmanager_products` p 
                            LEFT JOIN `productmanager_products-categories` pc 
                            ON p.id = pc.product_id 
                            WHERE pc.category_id IN (0,35) 

                            AND `price_sell` BETWEEN 1.83 
                            AND 20.45 
                            AND price_sell > 0
                            ORDER BY pc.ordering ASC 
                    ) A
                        inner join
                    (
                            SELECT DISTINCT `id`,`ref`,`spec_varc_titre_fr`,`price_sell`,`spec_bool_new`,`defaultmedia_id`
                            FROM `productmanager_products` p 
                            LEFT JOIN `productmanager_products-categories` pc 
                            ON p.id = pc.product_id 
                            WHERE pc.category_id IN (0,98) 

                            AND `price_sell` BETWEEN 1.83 
                            AND 20.45 
                            AND price_sell > 0
                            ORDER BY pc.ordering ASC 
                    ) B
                    ON A.`ref` = B.`ref`
                    LIMIT 0,15;
person Vincent Duprez    schedule 24.05.2014