小。速度很快。可靠。
选择任意三个选项。

SQLite与其他数据库引擎中的NULL处理

目标是使SQLite以符合标准的方式处理NULL。但是SQL标准中关于如何处理NULL看起来模棱两可。从标准文件中还不清楚NULL应该如何在任何情况下都要处理。

因此,与标准文档不同,各种流行的对SQL引擎进行了测试,以了解它们如何处理NULL。这个想法是为了让SQLite像所有其他引擎一样工作。志愿者开发并运行了一个SQL测试脚本SQL RDBMS和这些测试的结果用于推断每个引擎如何处理NULL值。最初的测试于2002年5月进行。本文档末尾提供了测试脚本的副本。

SQLite最初的编码方式是下表中的所有问题都是“是”。但是在其他SQL引擎上运行的实验表明,没有一个以这种方式工作。所以SQLite被修改为与Oracle、PostgreSQL和DB2。这涉及到制造NULL在SELECT DISTINCT语句中不明确用于SELECT中的UNION运算符。NULL仍然是不同的在UNIQUE列中。这似乎有点武断,但欲望与其他发动机兼容比反对意见更重要。

可以使SQLite将NULL视为不同于SELECT DISTINCT和UNION的目的。要做到这一点,应该更改中NULL_ALWAYS_DISTINCT#定义的值sqliteInt。小时源文件并重新编译。

2003年7月13日更新:由于本文档最初是由一些数据库引擎编写的测试已更新,用户已发送对下表的更正。原始数据显示出多种多样但随着时间的推移,行为的范围已经趋同PostgreSQL/Oracle模型。唯一的显著差异Informix和MS-SQL都将NULL视为在独特的列中模糊。

NULL对于UNIQUE列是不同的,但对于SELECT DISTINCT和UNION仍然令人困惑。看起来NULL应该在任何地方或任何地方都是不同的。以及SQL标准文件表明,NULL应该在任何地方都是不同的。然而,截至在本文中,没有经过测试的SQL引擎将SELECT中的NULL视为不同的DISTINCT语句或在UNION中。

下表显示了NULL处理实验的结果。

   数据库 PostgreSQL 甲骨文公司 Informix公司 DB2数据库 MS-SQL数据库 奥塞洛
向null中添加任何内容都会导致null 是的 是的 是的 是的 是的 是的 是的
将null乘以零即为null 是的 是的 是的 是的 是的 是的 是的
NULL在UNIQUE列中是不同的 是的 是的 是的 (注4) 是的
空值在SELECT distinct中是不同的
UNION中的null是不同的
“CASE WHEN null THEN 1 ELSE 0 END”为0? 是的 是的 是的 是的 是的 是的 是的
“null OR true”为true 是的 是的 是的 是的 是的 是的 是的
“not(null AND false)”为true 是的 是的 是的 是的 是的 是的 是的
   MySQL数据库
3.23.41
MySQL数据库
4.0.16
火鸟 SQL语言
随时随地
博兰德
数据库
向null中添加任何内容都会导致null 是的 是的 是的 是的 是的
零乘零得到零 是的 是的 是的 是的 是的
NULL在UNIQUE列中是不同的 是的 是的 是的 (注4) (注4)
空值在SELECT distinct中是不同的 否(注1)
UNION中的null是不同的 (注3) 否(注1)
“CASE WHEN null THEN 1 ELSE 0 END”为0? 是的 是的 是的 是的 (注5)
“null OR true”为true 是的 是的 是的 是的 是的
“not(null AND false)”为true 是的 是的 是的 是的
备注: 1.  旧版本的firebird省略了SELECT DISTINCT中的所有NULL和UNION。
2.  测试数据不可用。
3.  MySQL版本3.23.41不支持UNION。
4.  DB2、SQL Anywhere和Borland Interbase不允许在UNIQUE列中使用NULL。
5.  Borland Interbase不支持CASE表达式。

 

以下脚本用于收集表的信息以上。

--我已经决定SQL对NULL的处理是反复无常的,不能--由逻辑推导。它必须通过实验来发现。为此,我已经--准备了以下脚本来测试各种SQL数据库如何处理NULL。--我的目标是使用从这个脚本中收集的信息使SQLite成为--尽可能类似于其他数据库。----如果可以的话,请在数据库引擎中运行此脚本并将结果邮寄--发送给我drh@hwaci.com,这将是一个很大的帮助。请确保识别--用于此测试的数据库引擎。谢谢。----如果必须更改任何内容才能使此脚本与数据库一起运行--引擎,请将修改后的脚本与结果一起发送。----使用数据创建测试表创建表t1(a int,b int,c int);插入t1值(1,0,0);插入t1值(2,0,1);插入t1值(3,1,0);插入t1值(4,1,1);插入t1值(5,null,0);插入t1值(6,null,1);插入t1值(7,null,null);--检查CASE对其测试表达式中的NULL做了什么选择a,当b<>0时,选择1,否则0从t1结束;选择a+10,如果不是b<>0,则选择1,否则从t1结束0;选择a+20,当b<>0和c<>0时,1从t1结束;选择a+30,如果不是(b<>0和c<>0),则选择1,否则0从t1结束;选择a+40,如果b<>0或c<>0,则1从t1结束;选择a+50,如果不是(b<>0或c<>0),则选择1,否则0从t1结束;选择a+60,当c时为b,然后从t1开始为1,否则为0;选择a+70,当b时为c,然后从t1开始为1,否则为0;--当NULL乘以0时会发生什么?从t1中选择a+80,b*0;从t1中选择a+90,b*c;--其他运算符的NULL会发生什么情况?从t1开始选择a+100,b+c;--测试骨料操作员的待遇从t1中选择计数(*)、计数(b)、总和(b)和平均值(b),最小(b)或最大(b);--检查WHERE子句中NULL的行为从t1中选择a+110,其中b<10;从t1中选择a+120,其中b不大于10;从t1中选择a+130,其中b<10或c=1;从t1中选择a+140,其中b<10 AND c=1;从t1中选择a+150,其中不选择(b<10 AND c=1);从t1开始选择一个+160,其中不是(c=1 AND b<10);--检查DISTINCT查询中NULL的行为从t1中选择不同的b;--检查UNION查询中NULL的行为从t1联合中选择b从t1中选择b;--创建具有唯一列的新表。检查是否考虑NULL--与众不同。创建表t2(a int,b int unique);插入t2值(1,1);插入t2值(2,null);插入t2值(3,空);从t2中选择*;升降台t1;升降台t2;