使用INNER JOIN排除MYSQL查询结果

时间:2015-10-05 18:47:10

标签: mysql sql select subquery

我有两张桌子。第一本书充满了每本书book_id。第二个表是book_idkeyword_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。

我尝试了什么

以上查询是我最接近实现它的问题,但在这方面却失败了。

如何以最优化的方式实现预期结果?

4 个答案:

答案 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)

Demo here

答案 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子句中的相关子查询的方法更好。但是,如果性能很重要,那么建议您测试您正在考虑的替代方案。