MySQL NOT IN 子查询未按预期工作

Posted

技术标签:

【中文标题】MySQL NOT IN 子查询未按预期工作【英文标题】:MySQL NOT IN with subquery not working as expected 【发布时间】:2012-08-02 15:53:41 【问题描述】:

我正在创建一个应用程序,它将为电子邮件营销活动生成列表。我有用于联系人、电子邮件和活动的表格。一个活动有很多电子邮件,一个联系人有很多电子邮件。该电子邮件与联系人和活动相关。基本上是一个多对多关系的表,除了我在表中有其他字段用于电子邮件结果(单击、打开、取消订阅等)。还有其他表,但这是我遇到麻烦的地方。

我正在尝试将 NOT IN 与子查询一起使用,以获取自特定日期以来未收到电子邮件的联系人列表以及其他条件。一个示例查询是这样的:

SELECT * 
FROM `contact` `t` 
WHERE (unsubscribed='1')
  AND t.id NOT IN 
   (SELECT distinct contact_id 
    FROM email, campaign 
    WHERE email.campaign_id = campaign.id 
      AND campaign.date_sent >= '2012-07-12') 
ORDER BY rand() 
LIMIT 10000

这将返回 0 结果。但是,如果我运行第一个条件:

select id 
from contact 
where unsubscribed=1

我有 9075 行。然后,如果我单独运行子查询:

SELECT distinct contact_id 
FROM email, campaign 
WHERE email.campaign_id = campaign.id 
  AND campaign.date_sent >= '2012-07-12'

我有 116612 行。在每个结果中,我最终得到了 826 个重复值。据我了解,这意味着 9075-826=8249 记录是 unsubscribed=1 而不是在第二个查询中。所以,我的第一个查询应该返回 8249 个结果,但它返回 0。我一定是查询的结构错误或使用了错误的运算符,但我终生无法弄清楚如何正确处理。

有人可以帮忙吗?非常感谢,因为这让我难倒了 3 天! :)

【问题讨论】:

您是如何检查的:826 个重复值? 请给出SELECT * FROM email, campaign WHERE email.campaign_id = campaign.id AND campaign.date_sent >= '2012-07-12' AND contact_id IS NULL的结果 "据我所知,这意味着 9075-826=8249 条记录被取消订阅=1 并且不在第二个查询中。"嗯,没有。这意味着您有 116612 - 826 = 115786 个您不想包含的唯一联系人 ID。部分或全部 9075 联系人是否在该集合中,是另一个问题。 @Razvam - 我将结果导出到 Excel 并删除了重复项,这是它给我的数字。 @Roland,我不确定我是否理解你。第一个条件的结果给了我 9075 个未订阅的人。从那我想得到所有那些自 7 月 12 日以来没有收到电子邮件的人,所以我应该不能得到超过 9075 个结果。如果我对它的理解不正确,那么我需要重写查询。无论哪种方式,我的查询都返回 0 个结果,这与我们俩的想法背道而驰!感谢您迄今为止的所有帮助! 【参考方案1】:

这是因为

SELECT 1 FROM DUAL WHERE 1 NOT IN (NULL, 2) 

不会返回任何东西,而

SELECT 1 FROM DUAL WHERE 1 NOT IN (2)

会的。

请检查NOT INNULLmysql 中的行为。

出于您的担忧,您应该使用NOT EXISTS 而不是NOT IN 来解决它:

SELECT * FROM `contact` `t` 
WHERE (unsubscribed='1')
AND NOT EXISTS (
    SELECT * FROM email, campaign 
    WHERE 
        email.campaign_id = campaign.id 
    AND campaign.date_sent >= '2012-07-12'
    AND t.id = contact_id
) 
ORDER BY rand() 
LIMIT 10000

【讨论】:

嘿 Sebas,我已经尝试在查询中使用 NOT EXISTS,但它对我不起作用。这是我尝试过的: SELECT * FROM contact t WHERE (1=1) AND (unsubscribed='1') AND NOT EXISTS (SELECT distinct contact_id FROM email, campaign WHERE email.campaign_id = campaign.id AND campaign .date_sent >= '2012-07-01') ORDER BY rand() LIMIT 10000 。它给了我与上面使用 NOT IN 相同的结果。 嗨@BVBAccelerate,我添加了查询。问候。 它确实适用于这个查询,但只为我返回了 36 个结果,这是我没想到的。我会研究一些预期的结果,并将它们与我得到的结果进行比较,如果准确,我会告诉你。【参考方案2】:

只是在这上面浪费了几个小时和一些头发。

无法让“不存在”作为提到的公认答案工作。但是,您可以简单地在

中输入 NOT NULL

WHERE “您正在聚合的字段不为 NULL”,就完成了这项工作。

SELECT * 
FROM `contact` `t` 
WHERE (unsubscribed='1')
  AND t.id NOT IN 
   (SELECT distinct contact_id 
    FROM email, campaign 
    WHERE email.campaign_id = campaign.id 
      AND campaign.date_sent >= '2012-07-12'
      AND contact_id is not NULL          ###*************added line
) 
ORDER BY rand() 
LIMIT 10000

【讨论】:

【参考方案3】:
select c.*, e.id from contact as c 
left join email as e on c.id = e.contact_id and e.date_sent >= '2012-07-12' 
where e.id is null and c.unsubscribed = 1

我认为campaign.date_sent 是一个错字?必须是 email.date_sent?

【讨论】:

您为什么省略了电子邮件和广告系列之间的连接?看起来很重要。 一个活动的所有电子邮件都在某个日期发出,该日期是活动表中的 date_sent。而不是将 date_sent 放在每封电子邮件上,而是放在广告系列中。

以上是关于MySQL NOT IN 子查询未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

MySQL

MySQL

有什么学习MySQL的好教程吗?

MySQL 5.7 新增默认账号 mysql.session和mysql.sys

mysql 缺少mysql库怎么安装

MySQL数据库学习导航