diff options
Diffstat (limited to 'libraries/sqlite/unix/sqlite-3.5.1/www/nulls.tcl')
-rw-r--r-- | libraries/sqlite/unix/sqlite-3.5.1/www/nulls.tcl | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/libraries/sqlite/unix/sqlite-3.5.1/www/nulls.tcl b/libraries/sqlite/unix/sqlite-3.5.1/www/nulls.tcl new file mode 100644 index 0000000..9091389 --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/www/nulls.tcl | |||
@@ -0,0 +1,329 @@ | |||
1 | # | ||
2 | # Run this script to generated a nulls.html output file | ||
3 | # | ||
4 | set rcsid {$Id: nulls.tcl,v 1.8 2004/10/10 17:24:55 drh Exp $} | ||
5 | source common.tcl | ||
6 | header {NULL Handling in SQLite} | ||
7 | puts { | ||
8 | <h2>NULL Handling in SQLite Versus Other Database Engines</h2> | ||
9 | |||
10 | <p> | ||
11 | The goal is | ||
12 | to make SQLite handle NULLs in a standards-compliant way. | ||
13 | But the descriptions in the SQL standards on how to handle | ||
14 | NULLs seem ambiguous. | ||
15 | It is not clear from the standards documents exactly how NULLs should | ||
16 | be handled in all circumstances. | ||
17 | </p> | ||
18 | |||
19 | <p> | ||
20 | So instead of going by the standards documents, various popular | ||
21 | SQL engines were tested to see how they handle NULLs. The idea | ||
22 | was to make SQLite work like all the other engines. | ||
23 | A SQL test script was developed and run by volunteers on various | ||
24 | SQL RDBMSes and the results of those tests were used to deduce | ||
25 | how each engine processed NULL values. | ||
26 | The original tests were run in May of 2002. | ||
27 | A copy of the test script is found at the end of this document. | ||
28 | </p> | ||
29 | |||
30 | <p> | ||
31 | SQLite was originally coded in such a way that the answer to | ||
32 | all questions in the chart below would be "Yes". But the | ||
33 | experiments run on other SQL engines showed that none of them | ||
34 | worked this way. So SQLite was modified to work the same as | ||
35 | Oracle, PostgreSQL, and DB2. This involved making NULLs | ||
36 | indistinct for the purposes of the SELECT DISTINCT statement and | ||
37 | for the UNION operator in a SELECT. NULLs are still distinct | ||
38 | in a UNIQUE column. This seems somewhat arbitrary, but the desire | ||
39 | to be compatible with other engines outweighted that objection. | ||
40 | </p> | ||
41 | |||
42 | <p> | ||
43 | It is possible to make SQLite treat NULLs as distinct for the | ||
44 | purposes of the SELECT DISTINCT and UNION. To do so, one should | ||
45 | change the value of the NULL_ALWAYS_DISTINCT #define in the | ||
46 | <tt>sqliteInt.h</tt> source file and recompile. | ||
47 | </p> | ||
48 | |||
49 | <blockquote> | ||
50 | <p> | ||
51 | <i>Update 2003-07-13:</i> | ||
52 | Since this document was originally written some of the database engines | ||
53 | tested have been updated and users have been kind enough to send in | ||
54 | corrections to the chart below. The original data showed a wide variety | ||
55 | of behaviors, but over time the range of behaviors has converged toward | ||
56 | the PostgreSQL/Oracle model. The only significant difference | ||
57 | is that Informix and MS-SQL both threat NULLs as | ||
58 | indistinct in a UNIQUE column. | ||
59 | </p> | ||
60 | |||
61 | <p> | ||
62 | The fact that NULLs are distinct for UNIQUE columns but are indistinct for | ||
63 | SELECT DISTINCT and UNION continues to be puzzling. It seems that NULLs | ||
64 | should be either distinct everywhere or nowhere. And the SQL standards | ||
65 | documents suggest that NULLs should be distinct everywhere. Yet as of | ||
66 | this writing, no SQL engine tested treats NULLs as distinct in a SELECT | ||
67 | DISTINCT statement or in a UNION. | ||
68 | </p> | ||
69 | </blockquote> | ||
70 | |||
71 | |||
72 | <p> | ||
73 | The following table shows the results of the NULL handling experiments. | ||
74 | </p> | ||
75 | |||
76 | <table border=1 cellpadding=3 width="100%"> | ||
77 | <tr><th>  </th> | ||
78 | <th>SQLite</th> | ||
79 | <th>PostgreSQL</th> | ||
80 | <th>Oracle</th> | ||
81 | <th>Informix</th> | ||
82 | <th>DB2</th> | ||
83 | <th>MS-SQL</th> | ||
84 | <th>OCELOT</th> | ||
85 | </tr> | ||
86 | |||
87 | <tr><td>Adding anything to null gives null</td> | ||
88 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
89 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
90 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
91 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
92 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
93 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
94 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
95 | </tr> | ||
96 | <tr><td>Multiplying null by zero gives null</td> | ||
97 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
98 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
99 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
100 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
101 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
102 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
103 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
104 | </tr> | ||
105 | <tr><td>nulls are distinct in a UNIQUE column</td> | ||
106 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
107 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
108 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
109 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
110 | <td valign="center" align="center" bgcolor="#aaaad2">(Note 4)</td> | ||
111 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
112 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
113 | </tr> | ||
114 | <tr><td>nulls are distinct in SELECT DISTINCT</td> | ||
115 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
116 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
117 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
118 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
119 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
120 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
121 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
122 | </tr> | ||
123 | <tr><td>nulls are distinct in a UNION</td> | ||
124 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
125 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
126 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
127 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
128 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
129 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
130 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
131 | </tr> | ||
132 | <tr><td>"CASE WHEN null THEN 1 ELSE 0 END" is 0?</td> | ||
133 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
134 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
135 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
136 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
137 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
138 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
139 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
140 | </tr> | ||
141 | <tr><td>"null OR true" is true</td> | ||
142 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
143 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
144 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
145 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
146 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
147 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
148 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
149 | </tr> | ||
150 | <tr><td>"not (null AND false)" is true</td> | ||
151 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
152 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
153 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
154 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
155 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
156 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
157 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
158 | </tr> | ||
159 | </table> | ||
160 | |||
161 | <table border=1 cellpadding=3 width="100%"> | ||
162 | <tr><th>  </th> | ||
163 | <th>MySQL<br>3.23.41</th> | ||
164 | <th>MySQL<br>4.0.16</th> | ||
165 | <th>Firebird</th> | ||
166 | <th>SQL<br>Anywhere</th> | ||
167 | <th>Borland<br>Interbase</th> | ||
168 | </tr> | ||
169 | |||
170 | <tr><td>Adding anything to null gives null</td> | ||
171 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
172 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
173 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
174 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
175 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
176 | </tr> | ||
177 | <tr><td>Multiplying null by zero gives null</td> | ||
178 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
179 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
180 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
181 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
182 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
183 | </tr> | ||
184 | <tr><td>nulls are distinct in a UNIQUE column</td> | ||
185 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
186 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
187 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
188 | <td valign="center" align="center" bgcolor="#aaaad2">(Note 4)</td> | ||
189 | <td valign="center" align="center" bgcolor="#aaaad2">(Note 4)</td> | ||
190 | </tr> | ||
191 | <tr><td>nulls are distinct in SELECT DISTINCT</td> | ||
192 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
193 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
194 | <td valign="center" align="center" bgcolor="#c7a9a9">No (Note 1)</td> | ||
195 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
196 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
197 | </tr> | ||
198 | <tr><td>nulls are distinct in a UNION</td> | ||
199 | <td valign="center" align="center" bgcolor="#aaaad2">(Note 3)</td> | ||
200 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
201 | <td valign="center" align="center" bgcolor="#c7a9a9">No (Note 1)</td> | ||
202 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
203 | <td valign="center" align="center" bgcolor="#c7a9a9">No</td> | ||
204 | </tr> | ||
205 | <tr><td>"CASE WHEN null THEN 1 ELSE 0 END" is 0?</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> | ||
209 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
210 | <td valign="center" align="center" bgcolor="#aaaad2">(Note 5)</td> | ||
211 | </tr> | ||
212 | <tr><td>"null OR true" is true</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> | ||
218 | </tr> | ||
219 | <tr><td>"not (null AND false)" is true</td> | ||
220 | <td valign="center" align="center" bgcolor="#c7a9a9">No</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="#a9c7a9">Yes</td> | ||
224 | <td valign="center" align="center" bgcolor="#a9c7a9">Yes</td> | ||
225 | </tr> | ||
226 | </table> | ||
227 | |||
228 | <table border=0 align="right" cellpadding=0 cellspacing=0> | ||
229 | <tr> | ||
230 | <td valign="top" rowspan=5>Notes: </td> | ||
231 | <td>1. </td> | ||
232 | <td>Older versions of firebird omits all NULLs from SELECT DISTINCT | ||
233 | and from UNION.</td> | ||
234 | </tr> | ||
235 | <tr><td>2. </td> | ||
236 | <td>Test data unavailable.</td> | ||
237 | </tr> | ||
238 | <tr><td>3. </td> | ||
239 | <td>MySQL version 3.23.41 does not support UNION.</td> | ||
240 | </tr> | ||
241 | <tr><td>4. </td> | ||
242 | <td>DB2, SQL Anywhere, and Borland Interbase | ||
243 | do not allow NULLs in a UNIQUE column.</td> | ||
244 | </tr> | ||
245 | <tr><td>5. </td> | ||
246 | <td>Borland Interbase does not support CASE expressions.</td> | ||
247 | </tr> | ||
248 | </table> | ||
249 | <br clear="both"> | ||
250 | |||
251 | <p> </p> | ||
252 | <p> | ||
253 | The following script was used to gather information for the table | ||
254 | above. | ||
255 | </p> | ||
256 | |||
257 | <pre> | ||
258 | -- I have about decided that SQL's treatment of NULLs is capricious and cannot be | ||
259 | -- deduced by logic. It must be discovered by experiment. To that end, I have | ||
260 | -- prepared the following script to test how various SQL databases deal with NULL. | ||
261 | -- My aim is to use the information gather from this script to make SQLite as much | ||
262 | -- like other databases as possible. | ||
263 | -- | ||
264 | -- If you could please run this script in your database engine and mail the results | ||
265 | -- to me at drh@hwaci.com, that will be a big help. Please be sure to identify the | ||
266 | -- database engine you use for this test. Thanks. | ||
267 | -- | ||
268 | -- If you have to change anything to get this script to run with your database | ||
269 | -- engine, please send your revised script together with your results. | ||
270 | -- | ||
271 | |||
272 | -- Create a test table with data | ||
273 | create table t1(a int, b int, c int); | ||
274 | insert into t1 values(1,0,0); | ||
275 | insert into t1 values(2,0,1); | ||
276 | insert into t1 values(3,1,0); | ||
277 | insert into t1 values(4,1,1); | ||
278 | insert into t1 values(5,null,0); | ||
279 | insert into t1 values(6,null,1); | ||
280 | insert into t1 values(7,null,null); | ||
281 | |||
282 | -- Check to see what CASE does with NULLs in its test expressions | ||
283 | select a, case when b<>0 then 1 else 0 end from t1; | ||
284 | select a+10, case when not b<>0 then 1 else 0 end from t1; | ||
285 | select a+20, case when b<>0 and c<>0 then 1 else 0 end from t1; | ||
286 | select a+30, case when not (b<>0 and c<>0) then 1 else 0 end from t1; | ||
287 | select a+40, case when b<>0 or c<>0 then 1 else 0 end from t1; | ||
288 | select a+50, case when not (b<>0 or c<>0) then 1 else 0 end from t1; | ||
289 | select a+60, case b when c then 1 else 0 end from t1; | ||
290 | select a+70, case c when b then 1 else 0 end from t1; | ||
291 | |||
292 | -- What happens when you multiple a NULL by zero? | ||
293 | select a+80, b*0 from t1; | ||
294 | select a+90, b*c from t1; | ||
295 | |||
296 | -- What happens to NULL for other operators? | ||
297 | select a+100, b+c from t1; | ||
298 | |||
299 | -- Test the treatment of aggregate operators | ||
300 | select count(*), count(b), sum(b), avg(b), min(b), max(b) from t1; | ||
301 | |||
302 | -- Check the behavior of NULLs in WHERE clauses | ||
303 | select a+110 from t1 where b<10; | ||
304 | select a+120 from t1 where not b>10; | ||
305 | select a+130 from t1 where b<10 OR c=1; | ||
306 | select a+140 from t1 where b<10 AND c=1; | ||
307 | select a+150 from t1 where not (b<10 AND c=1); | ||
308 | select a+160 from t1 where not (c=1 AND b<10); | ||
309 | |||
310 | -- Check the behavior of NULLs in a DISTINCT query | ||
311 | select distinct b from t1; | ||
312 | |||
313 | -- Check the behavior of NULLs in a UNION query | ||
314 | select b from t1 union select b from t1; | ||
315 | |||
316 | -- Create a new table with a unique column. Check to see if NULLs are considered | ||
317 | -- to be distinct. | ||
318 | create table t2(a int, b int unique); | ||
319 | insert into t2 values(1,1); | ||
320 | insert into t2 values(2,null); | ||
321 | insert into t2 values(3,null); | ||
322 | select * from t2; | ||
323 | |||
324 | drop table t1; | ||
325 | drop table t2; | ||
326 | </pre> | ||
327 | } | ||
328 | |||
329 | footer $rcsid | ||