我有两张桌子。第一本书充满了每本书book_id
。第二个表是book_id
到keyword_id
关系表。
SELECT b.* FROM books_table b
INNER JOIN keywords_table k
ON b.book_id = k.book_id AND k.keyword_id NOT IN(1,2,3)
WHERE b.is_hardcover = 1
GROUP BY b.book_id
没有任何关于keyword_id 1,2或3的图书都附在任何图书上。
图书可以包含关键字1,2或3,只要他们在排除列表中附加了不的附加keyword_ids。
以上查询是我最接近实现它的问题,但在这方面却失败了。
如何以最优化的方式实现预期结果?
答案 0 :(得分:4)
你可以这样做
disabled
答案 1 :(得分:3)
正如您所指出的,此查询将生成任何至少包含一个不是1,2或3的关键字的图书,这不是您想要的。相反,您希望明确排除包含这些关键字的图书。 SELECT b.*
FROM books_table b
INNER JOIN keywords_table k
ON b.book_id = k.book_id
WHERE b.is_hardcover = 1
GROUP BY b.book_id
HAVING SUM(k.keyword_id = 1) =0
AND SUM(k.keyword_id = 2) =0
AND SUM(k.keyword_id = 3) =0
并非真正适合这里的工作。相反,您可以使用join
运算符:
exists
答案 2 :(得分:1)
您可以使用以下查询:
SELECT *
FROM books_table
WHERE is_hardcover = 1 AND
book_id NOT IN (SELECT book_id
FROM keywords_table
GROUP BY book_id
HAVING COUNT(CASE WHEN keyword_id IN (1,2,3) THEN 1 END) <> 0)
答案 3 :(得分:1)
你要求的是&#34;反加入&#34;的味道。有几种方法可以实现它;这是一个:
SELECT b.* FROM books_table b
LEFT JOIN keywords_table k
ON b.book_id = k.book_id AND k.keyword_id IN (1,2,3)
WHERE k.book_id IS NULL AND b.is_hardcover = 1
左连接将左表(books_table
)中的每一行与满足条件b.book_id = k.book_id AND k.keyword_id IN (1,2,3)
的右表的那些行匹配,和包含单个结果左表的每一行的行与右表的任何行都不匹配。过滤条件k.book_id IS NULL
与连接条件冲突,因此只能通过左行不匹配右行的那些行来满足。
请注意,对连接谓词和过滤谓词的条件赋值对于外连接(例如此连接)至关重要。另请注意,除非GROUP BY
可能包含重复的books_table
,否则不需要book_id
子句。
这种方法在实践中可能比基于WHERE
子句中的相关子查询的方法更好。但是,如果性能很重要,那么建议您测试您正在考虑的替代方案。