Null Handling in SQLite

rzk1 pts0 comments

NULL Handling in SQLite

Small. Fast. Reliable.<br>Choose any three.

Home<br>Menu<br>About<br>Documentation<br>Download<br>License<br>Support<br>Purchase

Search

About<br>Documentation<br>Download<br>Support<br>Purchase

Search Documentation<br>Search Changelog

NULL Handling in SQLite Versus Other Database Engines

The goal is<br>to make SQLite handle NULLs in a standards-compliant way.<br>But the descriptions in the SQL standards on how to handle<br>NULLs seem ambiguous.<br>It is not clear from the standards documents exactly how NULLs should<br>be handled in all circumstances.

So instead of going by the standards documents, various popular<br>SQL engines were tested to see how they handle NULLs. The idea<br>was to make SQLite work like all the other engines.<br>An SQL test script was developed and run by volunteers on various<br>SQL RDBMSes and the results of those tests were used to deduce<br>how each engine processed NULL values.<br>The original tests were run in May of 2002.<br>A copy of the test script is found at the end of this document.

SQLite was originally coded in such a way that the answer to<br>all questions in the chart below would be "Yes". But the<br>experiments run on other SQL engines showed that none of them<br>worked this way. So SQLite was modified to work the same as<br>Oracle, PostgreSQL, and DB2. This involved making NULLs<br>indistinct for the purposes of the SELECT DISTINCT statement and<br>for the UNION operator in a SELECT. NULLs are still distinct<br>in a UNIQUE column. This seems somewhat arbitrary, but the desire<br>to be compatible with other engines outweighed that objection.

It is possible to make SQLite treat NULLs as distinct for the<br>purposes of the SELECT DISTINCT and UNION. To do so, one should<br>change the value of the NULL_ALWAYS_DISTINCT #define in the<br>sqliteInt.h source file and recompile.

Update 2003-07-13:<br>Since this document was originally written some of the database engines<br>tested have been updated and users have been kind enough to send in<br>corrections to the chart below. The original data showed a wide variety<br>of behaviors, but over time the range of behaviors has converged toward<br>the PostgreSQL/Oracle model. The only significant difference<br>is that Informix and MS-SQL both treat NULLs as<br>indistinct in a UNIQUE column.

The fact that NULLs are distinct for UNIQUE columns but are indistinct for<br>SELECT DISTINCT and UNION continues to be puzzling. It seems that NULLs<br>should be either distinct everywhere or nowhere. And the SQL standards<br>documents suggest that NULLs should be distinct everywhere. Yet as of<br>this writing, no SQL engine tested treats NULLs as distinct in a SELECT<br>DISTINCT statement or in a UNION.

The following table shows the results of the NULL handling experiments.

SQLite<br>PostgreSQL<br>Oracle<br>Informix<br>DB2<br>MS-SQL<br>OCELOT

Adding anything to null gives null<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes

Multiplying null by zero gives null<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes

nulls are distinct in a UNIQUE column<br>Yes<br>Yes<br>Yes<br>No<br>(Note 4)<br>No<br>Yes

nulls are distinct in SELECT DISTINCT<br>No<br>No<br>No<br>No<br>No<br>No<br>No

nulls are distinct in a UNION<br>No<br>No<br>No<br>No<br>No<br>No<br>No

"CASE WHEN null THEN 1 ELSE 0 END" is 0?<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes

"null OR true" is true<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes

"not (null AND false)" is true<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes

MySQL<br>3.23.41<br>MySQL<br>4.0.16<br>Firebird<br>SQL<br>Anywhere<br>Borland<br>Interbase

Adding anything to null gives null<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes

Multiplying null by zero gives null<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes

nulls are distinct in a UNIQUE column<br>Yes<br>Yes<br>Yes<br>(Note 4)<br>(Note 4)

nulls are distinct in SELECT DISTINCT<br>No<br>No<br>No (Note 1)<br>No<br>No

nulls are distinct in a UNION<br>(Note 3)<br>No<br>No (Note 1)<br>No<br>No

"CASE WHEN null THEN 1 ELSE 0 END" is 0?<br>Yes<br>Yes<br>Yes<br>Yes<br>(Note 5)

"null OR true" is true<br>Yes<br>Yes<br>Yes<br>Yes<br>Yes

"not (null AND false)" is true<br>No<br>Yes<br>Yes<br>Yes<br>Yes

Notes:<br>1.<br>Older versions of firebird omit all NULLs from SELECT DISTINCT<br>and from UNION.

2.<br>Test data unavailable.

3.<br>MySQL version 3.23.41 does not support UNION.

4.<br>DB2, SQL Anywhere, and Borland Interbase<br>do not allow NULLs in a UNIQUE column.

5.<br>Borland Interbase does not support CASE expressions.

The following script was used to gather information for the table<br>above.

-- I have about decided that SQL's treatment of NULLs is capricious and cannot be<br>-- deduced by logic. It must be discovered by experiment. To that end, I have<br>-- prepared the following script to test how various SQL databases deal with NULL.<br>-- My aim is to use the information gathered from this script to make SQLite as<br>-- much like other databases as possible.<br>-- If you could please run this script in your database engine and mail the results<br>-- to me at drh@hwaci.com, that will be a big help. Please be sure to identify the<br>-- database engine you use for this test. Thanks.<br>-- If you have to change anything to get this script to run with your database<br>-- engine, please send your revised script together with your results.

-- Create a test table with data<br>create table t1(a int, b int, c int);<br>insert into t1 values(1,0,0);<br>insert into t1...

nulls null distinct sqlite script select

Related Articles