Mysql空表连接失败

时间:2018-05-05 03:11:04

标签: mysql null left-join

后台,我有一个cron作业,用于查询与帖子相关的关键字,如果找到该关键字,则会通过电子邮件向用户发送帖子。

cron作业每分钟运行一次,因此一旦用户通过电子邮件发送通知,就不应该再次发生通知。 运行以下查询:

Hotspot safepoints

当填充表keywords_posts kp时,查询按预期工作。

如果表keywords_posts kp为空,则查询将永远不会返回任何内容。 我试图通过添加到WHERE子句来解决这个问题:

SELECT DISTINCT p.id AS post_id, u.display_name, u.id AS user_id, u.email, k.keyword, k.id AS keyword_id
FROM posts p, user_subscriptions us, keywords_users ku, keywords k, users u
LEFT JOIN keyword_subscription_sent kss ON kss.user_id = u.id
LEFT JOIN keywords_posts kp ON kss.post_id = kp.post_id
WHERE us.keywords = 1
AND ku.user_id = u.id
AND ku.keyword_id = k.id
AND kp.keyword_id = k.id
#AND kss.user_id IS NULL AND kss.post_id IS NULL
LIMIT 0, 200

但是将此添加到WHERE子句将导致查询在任何时候都不会返回任何内容。

期望的结果是:

查询将返回除keywords_posts kp表中列出的所有行。

3 个答案:

答案 0 :(得分:1)

建议:

将需要列为非NULL的条件从WHERE子句重新定位到外连接的相应ON子句。

不要将旧式逗号语法(用于连接操作)与JOIN关键字语法混合使用。抛弃逗号语法并使用JOIN。并将连接条件移动到ON子句。

将条件移动到外部联接的ON子句将允许返回NULL值。

如果我们这样做WHERE子句,请注意条件

WHERE ( col = some_non_null_val AND col IS NULL ) 
保证

永远不会评估为TRUE。 (检查每个单独行的条件。)仅返回条件评估为TRUE的行。可能你打算用OR代替AND

但如果我们只是重新定位条件

,我们可以避免OR
         col = some_non_null_val 

到外连接的ON子句。

我犹豫是否提供示例查询作为演示。最初的查询是生产半笛卡尔积;例如,似乎是usersuser_subscriptions之间的交叉联接...与user_subscriptions匹配的唯一条件是keywords=1。所以我不理解规范。

OP报告查询返回了正确的结果,但我怀疑查询实际上是否满足预期的规范。我怀疑usersuser_subscriptions之间的匹配应该包含一些额外的标准。

如果没有更精确的规范,包括样本数据和预期输出的示例,我不能在良心上为OP用例提供示例SQL。

答案 1 :(得分:0)

我认为你的WHERE条件中的kp_keyword_id = k.id导致查询在kp为空的情况下不返回任何内容,请尝试将其放入JOIN中,使其变为这样

SELECT DISTINCT p.id AS post_id, u.display_name, u.id AS user_id, u.email, k.keyword, k.id AS keyword_id
FROM posts p, user_subscriptions us, keywords_users ku, keywords k, users u
LEFT JOIN keyword_subscription_sent kss ON kss.user_id = u.id
LEFT JOIN keywords_posts kp ON kss.post_id = kp.post_id AND kp.keyword_id = k.id 
WHERE us.keywords = 1
AND ku.user_id = u.id
AND ku.keyword_id = k.id
LIMIT 0, 200

答案 2 :(得分:0)

你好vveryone,谢谢你输入。

以下工作:

SELECT * FROM (SELECT u.id as user_id, u.email, u.display_name, k.id as keyword_id, k.keyword, p.id AS post_id, kp.post_id AS kp_post_id, kp.keyword_id AS kp_keyword_id,
ku.user_id AS ku_user_id, ku.keyword_id AS ku_keyword_id
FROM users u, keywords k, posts p, keywords_posts kp, user_subscriptions us, keywords_users ku
WHERE kp.post_id = p.id AND us.keywords = 1 AND kp.keyword_id = k.id AND ku.keyword_id = k.id AND u.id = ku.user_id
GROUP BY kp.post_id, u.id) AS ukp LEFT JOIN keyword_subscription_sent kss ON ukp.user_id = kss.user_id AND kss.post_id = ukp.post_id WHERE kss.post_id IS NULL