1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
3
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
4
<title>NULL Handling in SQLite</title>
5
<style type="text/css">
8
font-family: Verdana, sans-serif;
13
a:visited { color: #734559 }
15
.logo { position:absolute; margin:3px; }
31
.toolbar a { color: white; text-decoration: none; padding: 6px 12px; }
32
.toolbar a:visited { color: white; }
33
.toolbar a:hover { color: #044a64; background: white; }
35
.content { margin: 5%; }
36
.content dt { font-weight:bold; }
37
.content dd { margin-bottom: 25px; margin-left:20%; }
38
.content ul { padding:0px; padding-left: 15px; margin:0px; }
41
.se { background: url(images/se.gif) 100% 100% no-repeat #044a64}
42
.sw { background: url(images/sw.gif) 0% 100% no-repeat }
43
.ne { background: url(images/ne.gif) 100% 0% no-repeat }
44
.nw { background: url(images/nw.gif) 0% 0% no-repeat }
46
/* Things for "fancyformat" documents start here. */
47
.fancy img+p {font-style:italic}
48
.fancy .codeblock i { color: darkblue; }
49
.fancy h1,.fancy h2,.fancy h3,.fancy h4 {font-weight:normal;color:#044a64}
50
.fancy h2 { margin-left: 10px }
51
.fancy h3 { margin-left: 20px }
52
.fancy h4 { margin-left: 30px }
53
.fancy th {white-space:nowrap;text-align:left;border-bottom:solid 1px #444}
54
.fancy th, .fancy td {padding: 0.2em 1ex; vertical-align:top}
55
.fancy #toc a { color: darkblue ; text-decoration: none }
56
.fancy .todo { color: #AA3333 ; font-style : italic }
57
.fancy .todo:before { content: 'TODO:' }
58
.fancy p.todo { border: solid #AA3333 1px; padding: 1ex }
59
.fancy img { display:block; }
60
.fancy :link:hover, .fancy :visited:hover { background: wheat }
61
.fancy p,.fancy ul,.fancy ol { margin: 1em 5ex }
62
.fancy li p { margin: 1em 0 }
63
/* End of "fancyformat" specific rules. */
69
<div><!-- container div to satisfy validator -->
72
<img class="logo" src="images/sqlite370_banner.gif" alt="SQLite Logo"
74
<div><!-- IE hack to prevent disappearing logo--></div>
75
<div class="tagline">Small. Fast. Reliable.<br>Choose any three.</div>
77
<table width=100% style="clear:both"><tr><td>
78
<div class="se"><div class="sw"><div class="ne"><div class="nw">
79
<table width=100% style="padding:0;margin:0;cell-spacing:0"><tr>
82
<a href="about.html">About</a>
83
<a href="sitemap.html">Sitemap</a>
84
<a href="docs.html">Documentation</a>
85
<a href="download.html">Download</a>
86
<a href="copyright.html">License</a>
87
<a href="news.html">News</a>
88
<a href="support.html">Support</a>
91
gMsg = "Search SQLite Docs..."
92
function entersearch() {
93
var q = document.getElementById("q");
94
if( q.value == gMsg ) { q.value = "" }
95
q.style.color = "black"
96
q.style.fontStyle = "normal"
98
function leavesearch() {
99
var q = document.getElementById("q");
100
if( q.value == "" ) {
102
q.style.color = "#044a64"
103
q.style.fontStyle = "italic"
108
<div style="padding:0 1em 0px 0;white-space:nowrap">
109
<form name=f method="GET" action="http://www.sqlite.org/search">
110
<input id=q name=q type=text
111
onfocus="entersearch()" onblur="leavesearch()" style="width:24ex;padding:1px 1ex; border:solid white 1px; font-size:0.9em ; font-style:italic;color:#044a64;" value="Search SQLite Docs...">
112
<input type=submit value="Go" style="border:solid white 1px;background-color:#044a64;color:white;font-size:0.9em;padding:0 1ex">
116
</div></div></div></div>
118
<div class=startsearch></div>
122
<h2>NULL Handling in SQLite Versus Other Database Engines</h2>
126
to make SQLite handle NULLs in a standards-compliant way.
127
But the descriptions in the SQL standards on how to handle
128
NULLs seem ambiguous.
129
It is not clear from the standards documents exactly how NULLs should
130
be handled in all circumstances.
134
So instead of going by the standards documents, various popular
135
SQL engines were tested to see how they handle NULLs. The idea
136
was to make SQLite work like all the other engines.
137
An SQL test script was developed and run by volunteers on various
138
SQL RDBMSes and the results of those tests were used to deduce
139
how each engine processed NULL values.
140
The original tests were run in May of 2002.
141
A copy of the test script is found at the end of this document.
145
SQLite was originally coded in such a way that the answer to
146
all questions in the chart below would be "Yes". But the
147
experiments run on other SQL engines showed that none of them
148
worked this way. So SQLite was modified to work the same as
149
Oracle, PostgreSQL, and DB2. This involved making NULLs
150
indistinct for the purposes of the SELECT DISTINCT statement and
151
for the UNION operator in a SELECT. NULLs are still distinct
152
in a UNIQUE column. This seems somewhat arbitrary, but the desire
153
to be compatible with other engines outweighed that objection.
157
It is possible to make SQLite treat NULLs as distinct for the
158
purposes of the SELECT DISTINCT and UNION. To do so, one should
159
change the value of the NULL_ALWAYS_DISTINCT #define in the
160
<tt>sqliteInt.h</tt> source file and recompile.
165
<i>Update 2003-07-13:</i>
166
Since this document was originally written some of the database engines
167
tested have been updated and users have been kind enough to send in
168
corrections to the chart below. The original data showed a wide variety
169
of behaviors, but over time the range of behaviors has converged toward
170
the PostgreSQL/Oracle model. The only significant difference
171
is that Informix and MS-SQL both treat NULLs as
172
indistinct in a UNIQUE column.
176
The fact that NULLs are distinct for UNIQUE columns but are indistinct for
177
SELECT DISTINCT and UNION continues to be puzzling. It seems that NULLs
178
should be either distinct everywhere or nowhere. And the SQL standards
179
documents suggest that NULLs should be distinct everywhere. Yet as of
180
this writing, no SQL engine tested treats NULLs as distinct in a SELECT
181
DISTINCT statement or in a UNION.
187
The following table shows the results of the NULL handling experiments.
190
<table border=1 cellpadding=3 width="100%">
191
<tr><th>  </th>
201
<tr><td>Adding anything to null gives null</td>
202
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
203
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
204
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
205
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
206
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
207
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
208
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
210
<tr><td>Multiplying null by zero gives null</td>
211
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
212
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
213
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
214
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
215
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
216
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
217
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
219
<tr><td>nulls are distinct in a UNIQUE column</td>
220
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
221
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
222
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
223
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
224
<td valign="center" align="center" bgcolor="#aaaad2">(Note 4)</td>
225
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
226
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
228
<tr><td>nulls are distinct in SELECT DISTINCT</td>
229
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
230
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
231
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
232
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
233
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
234
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
235
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
237
<tr><td>nulls are distinct in a UNION</td>
238
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
239
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
240
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
241
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
242
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
243
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
244
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
246
<tr><td>"CASE WHEN null THEN 1 ELSE 0 END" is 0?</td>
247
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
248
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
249
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
250
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
251
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
252
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
253
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
255
<tr><td>"null OR true" is true</td>
256
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
257
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
258
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
259
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
260
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
261
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
262
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
264
<tr><td>"not (null AND false)" is true</td>
265
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
266
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
267
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
268
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
269
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
270
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
271
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
275
<table border=1 cellpadding=3 width="100%">
276
<tr><th>  </th>
277
<th>MySQL<br>3.23.41</th>
278
<th>MySQL<br>4.0.16</th>
280
<th>SQL<br>Anywhere</th>
281
<th>Borland<br>Interbase</th>
284
<tr><td>Adding anything to null gives null</td>
285
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
286
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
287
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
288
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
289
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
291
<tr><td>Multiplying null by zero gives null</td>
292
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
293
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
294
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
295
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
296
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
298
<tr><td>nulls are distinct in a UNIQUE column</td>
299
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
300
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
301
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
302
<td valign="center" align="center" bgcolor="#aaaad2">(Note 4)</td>
303
<td valign="center" align="center" bgcolor="#aaaad2">(Note 4)</td>
305
<tr><td>nulls are distinct in SELECT DISTINCT</td>
306
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
307
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
308
<td valign="center" align="center" bgcolor="#c7a9a9">No (Note 1)</td>
309
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
310
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
312
<tr><td>nulls are distinct in a UNION</td>
313
<td valign="center" align="center" bgcolor="#aaaad2">(Note 3)</td>
314
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
315
<td valign="center" align="center" bgcolor="#c7a9a9">No (Note 1)</td>
316
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
317
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
319
<tr><td>"CASE WHEN null THEN 1 ELSE 0 END" is 0?</td>
320
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
321
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
322
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
323
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
324
<td valign="center" align="center" bgcolor="#aaaad2">(Note 5)</td>
326
<tr><td>"null OR true" is true</td>
327
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
328
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
329
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
330
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
331
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
333
<tr><td>"not (null AND false)" is true</td>
334
<td valign="center" align="center" bgcolor="#c7a9a9">No</td>
335
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
336
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
337
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
338
<td valign="center" align="center" bgcolor="#a9c7a9">Yes</td>
342
<table border=0 align="right" cellpadding=0 cellspacing=0>
344
<td valign="top" rowspan=5>Notes: </td>
346
<td>Older versions of firebird omits all NULLs from SELECT DISTINCT
349
<tr><td>2. </td>
350
<td>Test data unavailable.</td>
352
<tr><td>3. </td>
353
<td>MySQL version 3.23.41 does not support UNION.</td>
355
<tr><td>4. </td>
356
<td>DB2, SQL Anywhere, and Borland Interbase
357
do not allow NULLs in a UNIQUE column.</td>
359
<tr><td>5. </td>
360
<td>Borland Interbase does not support CASE expressions.</td>
367
The following script was used to gather information for the table
372
-- I have about decided that SQL's treatment of NULLs is capricious and cannot be
373
-- deduced by logic. It must be discovered by experiment. To that end, I have
374
-- prepared the following script to test how various SQL databases deal with NULL.
375
-- My aim is to use the information gather from this script to make SQLite as much
376
-- like other databases as possible.
378
-- If you could please run this script in your database engine and mail the results
379
-- to me at drh@hwaci.com, that will be a big help. Please be sure to identify the
380
-- database engine you use for this test. Thanks.
382
-- If you have to change anything to get this script to run with your database
383
-- engine, please send your revised script together with your results.
386
-- Create a test table with data
387
create table t1(a int, b int, c int);
388
insert into t1 values(1,0,0);
389
insert into t1 values(2,0,1);
390
insert into t1 values(3,1,0);
391
insert into t1 values(4,1,1);
392
insert into t1 values(5,null,0);
393
insert into t1 values(6,null,1);
394
insert into t1 values(7,null,null);
396
-- Check to see what CASE does with NULLs in its test expressions
397
select a, case when b<>0 then 1 else 0 end from t1;
398
select a+10, case when not b<>0 then 1 else 0 end from t1;
399
select a+20, case when b<>0 and c<>0 then 1 else 0 end from t1;
400
select a+30, case when not (b<>0 and c<>0) then 1 else 0 end from t1;
401
select a+40, case when b<>0 or c<>0 then 1 else 0 end from t1;
402
select a+50, case when not (b<>0 or c<>0) then 1 else 0 end from t1;
403
select a+60, case b when c then 1 else 0 end from t1;
404
select a+70, case c when b then 1 else 0 end from t1;
406
-- What happens when you multiple a NULL by zero?
407
select a+80, b*0 from t1;
408
select a+90, b*c from t1;
410
-- What happens to NULL for other operators?
411
select a+100, b+c from t1;
413
-- Test the treatment of aggregate operators
414
select count(*), count(b), sum(b), avg(b), min(b), max(b) from t1;
416
-- Check the behavior of NULLs in WHERE clauses
417
select a+110 from t1 where b<10;
418
select a+120 from t1 where not b>10;
419
select a+130 from t1 where b<10 OR c=1;
420
select a+140 from t1 where b<10 AND c=1;
421
select a+150 from t1 where not (b<10 AND c=1);
422
select a+160 from t1 where not (c=1 AND b<10);
424
-- Check the behavior of NULLs in a DISTINCT query
425
select distinct b from t1;
427
-- Check the behavior of NULLs in a UNION query
428
select b from t1 union select b from t1;
430
-- Create a new table with a unique column. Check to see if NULLs are considered
432
create table t2(a int, b int unique);
433
insert into t2 values(1,1);
434
insert into t2 values(2,null);
435
insert into t2 values(3,null);