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 IN
和NULL
在mysql 中的行为。
出于您的担忧,您应该使用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 * FROMcontact
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 NULLWHERE “您正在聚合的字段不为 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 子查询未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章