MySQL возвращает отличные результаты для нескольких условий

0

У меня есть таблицы с листингами, категориями и один, который сопоставляет их друг другу. Таким образом, листинг может быть размещен в нескольких категориях. Что-то вроде следующего:

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? Будет ли это требовать определенного типа соединения?

  • 0
    Вы хотите исключить листинг из вашего набора результатов, если он не только в двух указанных вами категориях?
Теги:
join

3 ответа

2
Лучший ответ

Да, вы захотите использовать (другое) соединение. Я думаю, что это должно сделать следующее:

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

  • 0
    Большое спасибо, работал отлично
  • 1
    Вы должны будете продолжать присоединяться к таблице карт каждый раз, когда вам нужна другая категория с этим методом
Показать ещё 4 комментария
1

Это должно работать

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)
  • 0
    +1 за правильные соединения!
  • 0
    @pcampbell: SQL99 JOINs более точен
Показать ещё 1 комментарий
0

Как насчет этого...

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)
  • 0
    Это даже не будет работать, вы не можете иметь два WHERE в одном запросе.
  • 0
    Вы получаете точку :) исправлено

Ещё вопросы

Сообщество Overcoder
Наверх
Меню