У меня есть таблицы с листингами, категориями и один, который сопоставляет их друг другу. Таким образом, листинг может быть размещен в нескольких категориях. Что-то вроде следующего:
listings table
id
title
etc
categories table
id
category_name
etc
map table
listing_id
category_id
Когда мне нужно получить всю информацию для списков в пределах одной категории (в этом случае категория с идентификатором 18), следующее работает нормально:
SELECT *
FROM (`listings`, `map`)
WHERE `map`.`category_id` = 18
AND map.listing_id = listings.id
Моя проблема в том, как я могу сделать аналогичный тип запроса, но теперь мне нужно найти те отдельные списки, которые находятся в двух категориях. Например, что делать, если мне нужно вернуть только те отдельные списки, которые находятся в категории category_id = 18 AND category_id = 20? Будет ли это требовать определенного типа соединения?
Да, вы захотите использовать (другое) соединение. Я думаю, что это должно сделать следующее:
SELECT lst.`id`, lst.<column>, ...
FROM `listings` lst, `map` m, `map` m2
WHERE m.`category_id` = 18 AND m2.`category_id` = 20
AND m.`listing_id` = lst.`id`
AND m2.`listing_id` = lst.`id`
Другая версия, вдохновленная предложениями, но эта работа (примечание, я заменил id
на category_id
для ясности):
select l.listing_id
from listings l
join (select m.listing_id, count(*) as cnt from map m where
m.category_id in (18,20)
group by m.listing_id) cat_matches
on cat_matches.listing_id = l.listing_id
where cat_matches.cnt = 2; -- 2 is the number of distinct categories to match
Уродливый, а? И подзапрос может быть не таким эффективным... но:
select l.listing_id
from listings l
join map m on l.listing_id=m.listing_id
where m.category_id in (18,20)
group by l.listing_id
having COUNT(*)=2;
Вы можете исключить этот подзапрос, получив все нужные вам строки, а затем отфильтровывая их. Обратите внимание, что это решение предполагает, что строки в таблице карт уникальны (что должно быть так, поскольку PK следует определять как на listing_id
, так и на category_id
).
Это должно работать
select * from listings l
join map m on m.listing_id = l.id
join categories c on c.id = m.category_id
where c.id in (18, 20)
Как насчет этого...
select * from listings l, map m, categories c
where l.id = m.listing_id
and m.category_id = c.id
and (c.id = 18
or c.id = 20)
или
select * from listings l, map m, categories c
where l.id = m.listing_id
and m.category_id = c.id
and c.id in (18, 20)
WHERE
в одном запросе.