早期文章已经介绍了in ,exists在数据库如果遇到空值会发生数据失真的情况,前段时间,又有人问到这一点,本篇文章再次对mysql8.0/oracle19c/postgresql-14进行测试,对于表中存在空值的集中匹配情况进行解析。
插入测试数据
--text_a作为主表,id作为关联字段
create table text_a(id int ,txt varchar(10));
insert into text_a(id,txt)
values(1,'A');
insert into text_a(id,txt)
values(2,'A');
insert into text_a(id,txt)
values(3,'A');
insert into text_a(id,txt)
values(4,'A');
insert into text_a(id,txt)
values(5,'A');
insert into text_a(id,txt)
values(6,'A');
insert into text_a(id,txt)
values(7,'A');
--text_b作为匹配表,id作为关联字段
create table text_b(id int ,txt varchar(10));
insert into text_b(id,txt)
values(1,'B');
insert into text_b(id,txt)
values(2,'B');
insert into text_b(id,txt)
values(3,'B');
insert into text_b(id,txt)
values(4,'B');
insert into text_b(id,txt)
values(5,'B');
insert into text_b(id,txt)
values(8,'B');
select * from text_a where id = any (select id from text_b); --返回text_a全部结果
select * from text_a where id in (select id from text_b); --id = 6 7 符合预期
select * from text_a where exists (select 1 from text_b where text_a.id=text_b.id); --id = 6 7 符合预期
此测试在oracle/mysql/postgresql均做了测试,返回值均一致且符合预期
在非的逻辑中区别就不一样了。
select * from text_a where id <> any (select id from text_b);--返回text_a的全部结果 不及预期
select * from text_a where id not in (select id from text_b); ----id = 6 7 符合预期
select * from text_a where not exists (select 1 from text_b where text_a.id=text_b.id);
--id = 6 7 符合预期
在非的逻辑,<> any 的返回结果就不及预期,但是not in ,not exists 返回结果均符合
向匹配表中的关联字段中插入null 值
insert into text_b(id,txt)
values(null,'B');
测试语句,本文只是列出在MySQL中的测试,实际结果和Oracle postgresql三库的返回结果均为一致,不再一一列举
select * from text_a where id = any (select id from text_b);
select * from text_a where id in (select id from text_b);
select * from text_a where exists (select 1 from text_b where text_a.id=text_b.id);
以上测试语句结果均为一致,数据情况正常,
在非的逻辑中返回的结果差异就比较大了
select * from text_a where id not in (select id from text_b); --返回结果为空
select * from text_a where id <> any (select id from text_b); --返回结果为text_a表的全部数据
select * from text_a where not exists (select 1 from text_b where text_a.id=text_b.id);--返回结果为id 6 ,7 两条数据
在非的逻辑中,只有not exists 的返回结果符合 。
将以上text_a ,text_b 的主,副位置进行调换。
select * from text_b where id = any (select id from text_a);
select * from text_b where id in (select id from text_a);
select * from text_b where exists (select 1 from text_a where text_a.id=text_b.id);
以上情况哎Oracle/mysql/postgresql返回结果均为正常且符合预期。
在非逻辑的情况下
select * from text_b where id <> any (select id from text_a); --返回主表确实null值的全部结果,
select * from text_b where id not in (select id from text_a); --返回id = 8
select * from text_b where not exists (select 1 from text_a where text_a.id=text_b.id); --返回ID=8 ,null 符合预期
此时也只有not exists 返回结果符合预期。
此时text_a作为主表,text_b作为匹配表,向text_a中增加一个空值
insert into text_a(id,txt)
values(null,'A');
select * from text_a where id = any (select id from text_b);
select * from text_a where id in (select id from text_b);
select * from text_a where exists (select 1 from text_b where text_a.id=text_b.id);
在此语法中,测试了oracle/mysql/postgresql 返回结果均符合预期。
当在非的逻辑中
select * from text_a where id <> any (select id from text_b);--返回除了null的全部结果
select * from text_a where id not in (select id from text_b); --返回空值
select * from text_a where not exists (select 1 from text_b where text_a.id=text_b.id);
--返回结果中,多了一个null 不及预期
在本次测试了Oracle/mysql/postgresql ,三库返回情况均一致,三个语法均返回错误结果集。
总结
主/配 | 主null/配 | 主/配null | 主null/配null | |
in | true | true | true | true |
not in | true | false | false | false |
any | true | true | true | true |
<> any | false | false | false | false |
exists | true | true | true | true |
not exist | true | true | true | false |
主null :代表主库关联字段存在null值
配null:代表匹配表关联字段存在null值
主:代表主库关联字段”不“存在null值
配:代表匹配表关联字段”不“存在null值
true:代表返回结果符合预期
false:代表返回结果不符合预期。造成数据失真。