0

假设有 3 个表:BOOKS、TAGS 和 ASOC

+----------+  +----------+  +----------+
|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')

我得到的不良结果是每本书都被多次列出,每个标签 ASOC 条目一次。我只想要匹配的唯一书籍列表。我该怎么做呢?

提前致谢。

4

3 回答 3

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

您还可以使 JOIN 更高效:

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')
于 2013-07-04T19:30:00.723 回答
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')
                  )
        )
;

查询的结构使您真正想要的内容更加清晰。(我建议在真实数据上同时尝试两种方法;其中一种可能会比另一种表现更好。)

于 2013-07-04T19:31:00.680 回答
0

你说你想“匹配一组特定的标签”。如果我把它理解为“所有标签”,那么这是一个“set-within-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子句计算每个标签的出现次数。比较要求两个标签都在集合中。

顺便说一句,如果您想要匹配一标签的书籍,只需将 更改andor. 我喜欢这种方法的原因是因为查询非常灵活。只需更改having子句,您就可以表达许多不同的条件。

我还更改了您的查询以使用 ANSI 标准连接语法。您应该学习使用这种语法编写查询。

于 2013-07-04T19:34:04.357 回答