Ситуация такая.
Есть таблица с полями product_id и category_id. Связи много-много.
На входе: 1 — список категорий и 2 — список категорий-исключений.
На выходе: список товаров, входящие в категории первого списка, но не входящие в категории второго списка.
В общем, алгоритм топорный:
Делаю запрос выбора товаров по первому списку, получаю список товаров, потом в цикле для каждого товара (и каждой категории-исключения) делаю запрос примерно такого вида:
SELECT EXIST( SELECT 1 FROM table WHERE prod_id = cat_id_exclude)
Если 1, то не включаю товар в результирующий список, иначе включаю.
Вроде все работает, но когда выбираю большое количество категорий-исключений, все виснет очень надолго. Что тут можно оптимизировать?
ЗЫ: Сильно не ворчите, я с БД никогда не работал. А тут подруга попросила цены у нее в магазине повысить, вот и тыкаюсь, а времени совсем мало...
ЗЫЗЫ: PHP, MySQL, Joomla, Virtuemart
Здравствуйте, koenjihyakkei, Вы писали:
K>Ситуация такая. K>Есть таблица с полями product_id и category_id. Связи много-много. K>На входе: 1 — список категорий и 2 — список категорий-исключений. K>На выходе: список товаров, входящие в категории первого списка, но не входящие в категории второго списка.
А написать
Select * from table where
(product_id in category_1) and (product_id not in category_1)
Здравствуйте, koenjihyakkei, Вы писали:
K>Ситуация такая. K>Есть таблица с полями product_id и category_id. Связи много-много. K>На входе: 1 — список категорий и 2 — список категорий-исключений. K>На выходе: список товаров, входящие в категории первого списка, но не входящие в категории второго списка.
select ...
from products p
join categories c on c.Id = p.CategoryId
left join exclusion ex on c.Id = e.Id
where e.Id is null
И все, субд разберется что и как надо джоинить (циклы, merge, hash-join)
Правда в MySQL настолько убогий оптимизатор, что возможно придется хинтами пинать.
CREATE TABLE test
(
category_id int,
product_id int
);
INSERT INTO test
(category_id, product_id)
VALUES
(1, 10),
(1, 11),
(1, 12),
(1, 13),
(2, 12),
(2, 13),
(2, 14),
(2, 15),
(2, 16);
SELECT * FROM test WHERE (category_id IN (1,2)) AND (category_id NOT IN (2))
K>CREATE TABLE test
K> (
K> category_id int,
K> product_id int
K> );
K>INSERT INTO test
K>(category_id, product_id)
K>VALUES
K>(1, 10),
K>(1, 11),
K>(1, 12),
K>(1, 13),
K>(2, 12),
K>(2, 13),
K>(2, 14),
K>(2, 15),
K>(2, 16);
K>SELECT * FROM test WHERE (category_id IN (1,2)) AND (category_id NOT IN (2))
K>
K>Результат: K>CATEGORY_ID PRODUCT_ID K>1 10 K>1 11 K>1 12 K>1 13
K>а нужен такой K>CATEGORY_ID PRODUCT_ID K>1 10 K>1 11
K>То есть все продукты, входящие в обе категории должны исключаться.
Ну тогда вычтите результат второго запроса из первого и всё
SELECT product_id FROM test WHERE category_id IN(1)
MINUS
SELECT product_id FROM test WHERE category_id IN(2)
--------------------------------------------------------------
Правильно заданный вопрос содержит в себе половину ответа
Здравствуйте, AndrewN, Вы писали:
AN>Ну тогда вычтите результат второго запроса из первого и всё
AN>
AN>SELECT product_id FROM test WHERE category_id IN(1)
AN>MINUS
AN>SELECT product_id FROM test WHERE category_id IN(2)
AN>
Оказывается в Mysql нет оператора MINUS, но говорят LEFT JOIN делает то же самое, но проверить толком не смог, так как при гуглении увидел одну интересную конструкцию с вложенным селектом, решил попробовать у себя.. и взлетело как надо )
Получилось вот так:
SELECT product_id
FROM test
WHERE category_id IN(1,2)
AND product_id NOT IN(
SELECT product_id
FROM test
WHERE category_id IN(2))
Здравствуйте, koenjihyakkei, Вы писали:
K>Ситуация такая. K>Есть таблица с полями product_id и category_id. Связи много-много. K>На входе: 1 — список категорий и 2 — список категорий-исключений. K>На выходе: список товаров, входящие в категории первого списка, но не входящие в категории второго списка.
SELECT distinct product_id
FROM test
WHERE
category_id IN (1,2) AND
not exists (select * from test excl where excl.product_id = test.product_id and excl.category_id IN (2))
Здравствуйте, koenjihyakkei, Вы писали:
K>Ситуация такая. K>Есть таблица с полями product_id и category_id. Связи много-много. K>На входе: 1 — список категорий и 2 — список категорий-исключений. K>На выходе: список товаров, входящие в категории первого списка, но не входящие в категории второго списка.
K>В общем, алгоритм топорный: K>Делаю запрос выбора товаров по первому списку, получаю список товаров, потом в цикле для каждого товара (и каждой категории-исключения) делаю запрос примерно такого вида: K>
K>SELECT EXIST( SELECT 1 FROM table WHERE prod_id = cat_id_exclude)
K>
K>Если 1, то не включаю товар в результирующий список, иначе включаю.
K>Вроде все работает, но когда выбираю большое количество категорий-исключений, все виснет очень надолго. Что тут можно оптимизировать?
Написать сразу одним запросом, естественно.
У тебя тупо если много категорий-исключений, то много походов к серверу, а именно их Кол-во выбранных товаров * кол-во категорий -исключений.
Здравствуйте, MasterZiv, Вы писали:
MZ>Написать сразу одним запросом, естественно. MZ>У тебя тупо если много категорий-исключений, то много походов к серверу, а именно их Кол-во выбранных товаров * кол-во категорий -исключений.