2013-07-04 2 views
0

Предположим, есть 3 таблицы: книги, TAGS и АСОКSQL присоединиться запрос возвращения строки для каждого соответствия АСОК

+----------+ +----------+ +----------+ 
|BOOKS  | |TAGS  | |ASOC  | 
+----------+ +----------+ +----------+ 
|book_id | |tag_id | |book_id | 
|book_name | |tag  | |tag_id | 
|...  | +----------+ +----------+ 
+----------+ 

Будем надеяться, что использование/намерения в этом примере очевидно ..

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

SELECT B.book_name 
FROM BOOKS B 
,  TAGS T 
,  ASOC A 
WHERE B.book_id = A.book_id 
AND T.tag_id = A.tag_id 
AND (T.tag = 'Classic' OR T.tag = 'Fiction') 

Нежелательный результат, который я получаю, что каждая книга в настоящее время в списке несколько раз, один раз для каждой записи тега АСОК. Мне просто нужен уникальный список книг, которые соответствуют. Как мне это сделать?

Заранее спасибо.

+0

Вы можете добавить предложение DISTINCT. –

+0

MSDN [статья об удалении повторяющихся строк с разным] (http://msdn.microsoft.com/en-us/library/ms187831%28v=sql.90%29.aspx) SQL-скрипт кода [http: // sqlfiddle.com/#!3/9a39a/1](http://sqlfiddle.com/#!3/9a39a/1) – deeg

ответ

0

Самый простой способ изменить SELECT B.book_name - SELECT DISTINCT B.book_name; однако, было бы лучше написать:

SELECT book_name 
    FROM books 
WHERE book_id IN 
     (SELECT book_id 
      FROM asoc 
      WHERE tag_id IN 
        (SELECT tag_id 
         FROM tags 
        WHERE tag IN ('Classic', 'Fiction') 
       ) 
     ) 
; 

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

0

Используйте DISTINCT, чтобы получить уникальный список:

SELECT DISTINCT B.book_name 
FROM BOOKS B 
,  TAGS T 
,  ASOC A 
WHERE B.book_id = A.book_id 
AND T.tag_id = A.tag_id 
AND (T.tag = 'Classic' OR T.tag = 'Fiction') 

В качестве дополнительного аксессуара, что последняя строка может быть переписан, чтобы быть немного более читаемым:

AND T.tag IN ('Classic', 'Fiction') 

Вы также можете сделать стыки более эффективная:

SELECT DISTINCT B.book_name 
FROM BOOKS B 
     INNER JOIN ASOC A on B.book_id = A.book_id 
     INNER JOIN TAGS T on A.tag_id = T.tag_id 
WHERE T.tag IN ('Classic', 'Fiction') 
0

Вы говорите, что хотите «сопоставить определенный набор тегов». Если я принимаю это как «все теги», то это запрос «set-in-sets». Я хотел бы решить их с помощью агрегации:

SELECT B.book_name 
FROM BOOKS B join 
     ASOC A 
     on B.book_id = A.book_id 
     TAGS T 
     on T.tag_id = A.tag_id 
group by B.book_name 
having sum(case when t.tag = 'Classic' then 1 else 0 end) > 0 and 
     sum(case when t.tag = 'Fiction' then 1 else 0 end) > 0; 

Предложение having рассчитывает количество вхождений каждого тэга. Для сравнения необходимо, чтобы в наборе были теги.

Кстати, если вы хотите, книги, которые соответствуют либо тег, просто изменить and к or. Причина, по которой мне нравится этот подход, заключается в том, что запрос довольно гибкий. Вы можете выразить много разных условий, просто изменив предложение having.

Я также поменял ваш запрос на использование стандартного синтаксиса объединения ANSI. Вы должны научиться писать запросы с помощью этого синтаксиса.

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