这就像我拿着它@sgeddes。在写作时,我意识到它只是让人们的目光掠过。
SQL NOT IN()危险
create table mStatus
( id int auto_increment primary key,
status varchar(10) not null
);
insert mStatus (status) values ('single'),('married'),('divorced'),('widow');
create table people
( id int auto_increment primary key,
fullName varchar(100) not null,
status varchar(10) null
);
Chunk1:
truncate table people;
insert people (fullName,status) values ('John Henry','single');
select * from mstatus where status not in (select status from people);
** 3行,按预期**
Chunk2:
truncate table people;
insert people (fullName,status) values ('John Henry','single'),('Kim Billings',null);
select * from mstatus where status not in (select status from people);
没有行,嗯?
显然这是'不正确的'。它来源于SQL使用三值逻辑, 由NULL的存在驱动,非值表示缺少(或未知)信息。 随着NOT IN,Chunk2它被翻译这样的:
status NOT IN ('married', 'divorced', 'widowed', NULL)
这相当于:
NOT(status='single' OR status='married' OR status='widowed' OR status=NULL)
“状态= NULL” 的计算结果为UNKNOWN和,根据三规则表达价值逻辑, NOT UNKNOWN也评估为UNKNOWN。结果,所有行都被过滤掉,查询返回一个空集。
可能的解决方案包括:
select s.status
from mstatus s
left join people p
on p.status=s.status
where p.status is null
或使用not exists
@Drew - 正确 - 空值不是可以根据期望的结果是一个问题。左连接/空检查可能是首选/最优的。不存在可能会对性能产生影响。像往常一样,只取决于... – sgeddes
试图重新安置一篇我曾经偶然发现的关于一个团队花了2个小时试图弄清楚'不在'做了一个坏转变的文章!谢谢。 – Drew
@德鲁 - 这是比较方法的好贴子。一般来说,我更喜欢使用存在,但MySQL不同意我:) http://explainextended.com/2009/09/18/not-in-vs-not-exists-vs-left-join-is-null- mysql/ – sgeddes