简介
今天看到白鳝老师的一篇文章说《你的PG数据安全准确吗》,主要讲postgresql数据库在数据文件丢失的情况下,对其增、删、改、查不会报错,但是数据会出现失真,所以今天想写一篇在开发人员使用数据库中使用in ,exists,any语法造成数据失真的情况。早前关于此类问题在我CSDN博客有过发表。
本文以postgresql14.7\mysql8.0.26\oracle19C 三个数据库版本进行试验
插入测试数据
--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');
1.主表、匹配表均无空值的情况。
select * from text_a where id = any (select id from text_b); --排除id = 6 7 符合预期
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 符合预期
此时主表和匹配表在没有NULL值得情况,返回的结果集均符合预期,没有出现数据失真
此测试在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 符合预期
此测试在oracle/mysql/postgresql均做了测试,返回值均一致
2.主表无空值,匹配表有空值。
向匹配表中的关联字段中插入null 值
insert into text_b(id,txt) values(null,'B');
测试其返回结果
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 两条数据 符合预期
主表有空值,匹配表无空值。
将以上text_a ,text_b 的主,副位置进行调换。
select * from text_b where id = any (select id from text_a); --返回id=1、2、3、4、5 符合预期
select * from text_b where id in (select id from text_a);--返回id=1、2、3、4、5 符合预期
select * from text_b where exists (select 1 from text_a where text_a.id=text_b.id);--返回id=1、2、3、4、5 符合预期
其实以上逻辑都是一个内连接的关系,当主副表互换位置,数据结果就返回正常了。
以上情况在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); --返回ID=1、2、3、4、5均符合预期
select * from text_a where id in (select id from text_b);--返回ID=1、2、3、4、5均符合预期
select * from text_a where exists (select 1 from text_b where text_a.id=text_b.id);--返回ID=1、2、3、4、5均符合预期
此时结果返回均正常
有意思的来了,在非逻辑的情况下就不一样了
select * from text_a where id <> any (select id from text_b);--返回id=1、2、3、4、5、6、7的全部结果
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); --返回id=6、7、null 不及预期
以上结果返回值均不一样,且均不符合预期,均发生数据失真的情况。
总结
主null :代表主库关联字段存在null值
配null:代表匹配表关联字段存在null值
主:代表主库关联字段”不“存在null值
配:代表匹配表关联字段”不“存在null值
true:代表返回结果符合预期
false:代表返回结果不符合预期。造成数据失真。
白鳝老师的今日一篇文章说《你的PG数据安全准确吗》感兴趣的话可以看看我后面的转载。