目的是使SQLite以符合标准的方式处理NULL。但是,SQL标准中有关如何处理NULL的描述似乎模棱两可。从标准文档中尚不清楚在所有情况下应如何正确处理NULL。
因此,无需遵循标准文档,而是对各种流行的SQL引擎进行了测试,以了解它们如何处理NULL。这个想法是使SQLite像所有其他引擎一样工作。由志愿者开发并在各种SQL RDBMS上运行SQL测试脚本,这些测试的结果用于推论每个引擎如何处理NULL值。原始测试在2002年5月运行。在该文档的末尾找到了测试脚本的副本。
SQLite最初的编码方式是,下表中所有问题的答案均为“是”。但是在其他SQL引擎上运行的实验表明,没有一个以这种方式工作。因此,对SQLite进行了修改,使其与Oracle,PostgreSQL和DB2相同。对于SELECT DISTINCT语句和SELECT中的UNION运算符,这涉及使NULL难以区分。NULL在UNIQUE列中仍然是不同的。这似乎有些武断,但与其他引擎兼容的愿望胜过了这一反对。
出于SELECT DISTINCT和UNION的目的,可以使SQLite将NULL区别对待。为此,应在sqliteInt.h源文件中更改NULL_ALWAYS_DISTINCT #define的值, 然后重新编译。
2003年7月13日更新: 自从本文档最初编写以来,一些经过测试的数据库引擎已经更新,并且用户已经足够友好地发送对以下图表的更正。原始数据显示了各种各样的行为,但是随着时间的流逝,行为的范围已经趋向于PostgreSQL / Oracle模型。唯一的显着区别是Informix和MS-SQL都将NULL视为UNIQUE列中的NULL。
NULL对于UNIQUE列是不同的,而对于SELECT DISTINCT和UNION却不明显,这一事实仍然令人困惑。似乎NULL应该在任何地方都没有区别,或者在任何地方都没有区别。SQL标准文档建议NULL在任何地方都应该是不同的。但是,在撰写本文时,没有经过测试的SQL引擎在SELECT DISTINCT语句或UNION中将NULL视为不同的。
下表显示了NULL处理实验的结果。
SQLite的 | PostgreSQL的 | 甲骨文 | Informix | DB2 | 微软SQL | 豹猫 | |
---|---|---|---|---|---|---|---|
将任何内容添加到null都会得到null | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 |
将null乘以零得到null | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 |
null在UNIQUE列中是唯一的 | 是的 | 是的 | 是的 | 不 | (注4) | 不 | 是的 |
在SELECT DISTINCT中null是不同的 | 不 | 不 | 不 | 不 | 不 | 不 | 不 |
null在UNION中是不同的 | 不 | 不 | 不 | 不 | 不 | 不 | 不 |
“ CASE WHEN null THEN 1 ELSE 0 END时的情况”是0? | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 |
“ null OR true”为true | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 |
“不是(null和false)”为true | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 | 是的 |
MySQL 3.23.41 |
MySQL 4.0.16 |
火鸟 | SQL Anywhere |
Borland Interbase |
|
---|---|---|---|---|---|
将任何内容添加到null都会得到null | 是的 | 是的 | 是的 | 是的 | 是的 |
将null乘以零得到null | 是的 | 是的 | 是的 | 是的 | 是的 |
null在UNIQUE列中是唯一的 | 是的 | 是的 | 是的 | (注4) | (注4) |
在SELECT DISTINCT中null是不同的 | 不 | 不 | 否(注1) | 不 | 不 |
null在UNION中是不同的 | (注3) | 不 | 否(注1) | 不 | 不 |
“ CASE WHEN null THEN 1 ELSE 0 END时的情况”是0? | 是的 | 是的 | 是的 | 是的 | (注5) |
“ null OR true”为true | 是的 | 是的 | 是的 | 是的 | 是的 |
“不是(null和false)”为true | 不 | 是的 | 是的 | 是的 | 是的 |
笔记: | 1。 | 较早版本的firebird省略了SELECT DISTINCT和UNION中的所有NULL。 |
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,否则0从t1结束; 选择a + 20,当b <> 0和c <> 0时,则1否则0从t1结束; 选择a + 30,如果不是(b <> 0和c <> 0),则1否则0从t1结束; 选择a + 40,当b <> 0或c <> 0时,则1否则0从t1结束; 选择a + 50,如果不是(b <> 0或c <> 0),则选择1,否则0从t1结束; 选择a + 60,在b时为c的情况下,然后从1到1否则为0结束; 选择a + 70,在c时为b,然后1否则0从t1结束的情况下; -当您将NULL乘以零时会发生什么? 从t1中选择a + 80,b * 0; 从t1中选择a + 90,b * c; -对于其他运算符,NULL将如何处理? 从t1中选择a + 100,b + c; -测试骨干算子的处理方式 从t1中选择count(*),count(b),sum(b),avg(b),min(b),max(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选择a + 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,null); 从t2中选择*; 下降表t1; 下降表t2;