2014-11-24 4 views
0

Рассмотрим эти три таблицы:Выберите новости, присоединиться по нескольким тегам

Новости (Столбцы: ID и т.д.)

News_Tag_Cross (Столбцы: ID, NewSID, TagID)

Тэги (Столбцы: Идентификатор, имя)

Как получить все статьи новостей, которые имеют два тега: «Дилер» И «Клиенты»?

я могу запустить этот запрос для обоих тегов & UNION результаты, но возвращает строки для каждой Dealer тега или Client тега. Очевидно, что я хочу вернуть новостные статьи, которые соединены с обоими.

SELECT n.id FROM news 
INNER JOIN news_tag_cross ntc 
    ON ntc.newsid=n.id 
INNER JOIN tags t 
    ON t.id=ntc.tagid 
WHERE news_tag_cross.tagID = 'DealerID' 

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

+1

раздавать имена таблиц? Это немного параноидально, не так ли? Обратите внимание, что 'id' в таблице' news_tags_cross', как представляется, не имеет никакой цели. – Strawberry

+0

Безопасность и упрощение. PS. У идентификатора всегда есть цель. – coderMe

+0

Ах, звучит, как говорит Селко – Strawberry

ответ

1

Вы можете использовать агрегацию с пунктом having:

SELECT n.id 
FROM news INNER JOIN 
    news_tag_cross ntc 
    ON ntc.newsid = n.id INNER JOIN 
    tags t 
    ON t.id = ntc.tagid 
GROUP BY n.id 
HAVING SUM(t.name = 'Dealer') > 0 AND 
     SUM(t.name = 'Client') > 0; 

Есть другие способы выразить это (в частности, с использованием соединения). Мне нравится этот метод, потому что предложение having может быть довольно гибким в отношении условий включения или исключения.

+0

Можете ли вы сделать это в MSSQL, или просто MySQL? 'select * от пользователей u, имеющих SUM (u.UserName = 'XYZ')> 0' throws синтаксис в MSSQL – franglais

+0

Я изменил t.name на t.id, и это работает красиво. Спасибо! – coderMe

0

Как насчет простого подзапроса:

SELECT news.* FROM news WHERE id = 
(SELECT NewsID FROM news_tag_cross 
JOIN tags ON news_tag_cross.tagid=tags.id 
WHERE tags.Name="Dealer" OR tabs.Name="Clients" 
) AS tbl 

(следить за капитализацией, она отличается в вашем описании против вашего примера кода)

+0

Ваш запрос ничего не вернет, поскольку столбец «Имя» может быть только одним значением или другим ... вам понадобится его как OR – DRapp

+0

@DRapp, LOL, я получил его таким образом и изменил его после перечитывания «и "в комментариях ОП. Конечно, вы правы, и я его редактирую. ;) – Sablefoste

+0

Я не думаю, что И ИЛИ или ИЛИ будут работать. Мне нужно выбрать, где элемент новостей соединяется с тегом Dealer и Client. ИЛИ вернет тот или другой, правильно? – coderMe

0

Мой подход к этому типу запроса должен сделать через соединение, но имеет первое предложение WHERE по одному критерию и соединение на основе второго. Таким образом, вы не ищете для всех записей новостей ID, а затем выбросить их, если они не имеют что-то ...

select 
     n.* 
    from 
     tags t 
     JOIN News_Tag_Cross ntc 
      on t.id = ntc.TagID 
      JOIN News_tag_Cross ntc2 
       on ntc.NewsID = ntc2.NewsID 
       Join Tags t2 
       on ntc2.tagID = t2.id 
       AND t2.Name = 'Client' 
      JOIN News n 
       on ntc.NewsID = n.ID 
    where 
     t.name = 'Dealer' 

Может быть немного больше, но я бы индекс по таблице тегов оба способа разрешить первое предложение WHERE и снова в предложении JOIN.

table   indexed on 
tags   (id, name) <-- for the JOIN clause 
tags   (name) <-- for the outermost WHERE clause 
News_tag_Cross (tagID, newsID) 

Чтобы уточнить ... скажем, у вас есть 100 000 записей новостей, и только 200 имеют ключевое слово «Дилер». Вместо того, чтобы запрашивать всю таблицу и группировать по ключевым словам, я ЗАПУСКАЮТ только те записи «Дилер». Исходя из этого, отправляемся в таблицу news_tag_cross ТОЛЬКО для этих новостей и ищем вторичный тег «Клиент». Готово.

+0

Это выглядит действительно интересно, я бы не подумал о создании второго псевдонима. На данный момент я достиг своей цели, но я сделаю еще несколько тестов с этим запросом, когда у меня появится шанс. – coderMe

0

Вы забыли news назвать

SELECT n.id FROM news n 
INNER JOIN news_tag_cross ntc 
    ON ntc.newsid=n.id 
INNER JOIN tags t 
    ON t.id=ntc.tagid 
WHERE ntc.tagID = 'DealerID' 

но ВЫБРАТЬ только в n.id и WHERE только в ntc.tagID то вполне кусок РЕГИСТРИРУЙТЕСЬ

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