使用 INNER JOIN 排除 MYSQL 查询结果
Posted
技术标签:
【中文标题】使用 INNER JOIN 排除 MYSQL 查询结果【英文标题】:Excluding MYSQL query results with an INNER JOIN 【发布时间】:2016-01-02 12:41:18 【问题描述】:我有两张桌子。第一个充满了书籍,每本书都有一个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,只要它们附加了排除列表中不的附加关键字 ID。
我试过的
上面的查询是我最接近实现它的方法,但在这方面它失败了。
我怎样才能以最优化的方式达到预期的结果?
【问题讨论】:
希望得到“没有...的书”的结果会让自己和他人感到困惑。 请注意,选择除分组列和组的聚合函数之外的列不是有效的 SQL。它对你有用,因为 mysql 支持它作为扩展。如果 MySQL 是您唯一关心的环境,那很好,但您应该在知情的情况下做出该决定,而不是默认。 【参考方案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
【讨论】:
这似乎会漏掉根本没有指定关键字的书籍。 @JohnBollinger 是的。我进行了修改以纠正问题。【参考方案2】:您要求的是“反加入”的味道。有几种方法可以实现它;这是一个:
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
s。
这种方法在实践中可能比基于WHERE
子句中的相关子查询的方法执行得更好。但是,如果性能很重要,那么建议您测试正在考虑的替代方案。
【讨论】:
【参考方案3】:如您所述,此查询将生成至少有一个关键字不是 1、2 或 3 的任何书籍,这不是您想要的。相反,您希望明确排除带有这些关键字的书籍。 join
并不是真正适合这里的工作。相反,您可以使用 exists
运算符:
SELECT b.*
FROM books_table b
WHERE b.is_hardcover = 1 AND
NOT EXISTS (SELECT *
FROM keywords_table k
WHERE b.book_id = k.book_id AND
k.keyword_id IN (1,2,3))
【讨论】:
【参考方案4】:你可以这样做
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
【讨论】:
对于延迟接受您的回答深表歉意!在不得不搁置这个项目之后,我花了四个月的时间才终于再次回到这个项目,我没有意识到我把这个悬而未决。这是我采用的解决方案。它工作得很好,并且在潜在的巨大关系表上没有第二次查询。非常感谢您的帮助!以上是关于使用 INNER JOIN 排除 MYSQL 查询结果的主要内容,如果未能解决你的问题,请参考以下文章
Mysql 多表连接查询 inner join 和 outer join 的使用
Mysql 连接(left join, right join, inner join ,full join)
mysql的unionleft join right join inner join和视图学习