In SQLite null is not equal to anything, including null.

I'm not sure what the best solution for your application is.  With help from 
the others here, I have learned to use coalesce() to convert nulls into a 
value, and to not allow null in key fields.

select 
  tableA.path,
  tableA.value 
from
  tableA,
  tableB 
where  
  tableA.path = tableB.path 
  and coalesce(tableA.value, '' ) = coalesce(tableB.value, '' );

yields 

alpha|1
gamma|

And it appears to use the myIndexB index for the join.

 -Clark

----- Original Message ----
From: Sean Cunningham <[EMAIL PROTECTED]>
To: sqlite-users@sqlite.org
Sent: Friday, June 15, 2007 1:26:49 PM
Subject: [sqlite] Optimization of equality comparison when NULL involved

I am hoping there is an obvious answer to this that I've overlooked.

I have two tables:

create table tableA (path TEXT, value TEXT);
create index myIndexA on tableA (path, value);

create table tableB(path TEXT, value TEXT);
create index myIndexB on tableB (path, value);


Now some simple inserts:

insert into tableA(path,value) values('alpha', '1');
insert into tableA(path,value) values('beta', '2');
insert into tableB(path,value) values('alpha', '1');
insert into tableB(path,value) values('beta', '999');

The following select statement gets what you'd expect, and it uses  
the index.

sqlite> select tableA.path, tableA.value from tableA,tableB where  
tableA.path=tableB.path and tableA.value=tableB.value;
alpha|1
gamma|3


However, if your data has NULL's:

insert into tableA(path,value) values('gamma', NULL);
insert into tableB(path,value) values('gamma', NULL);

The same select above neglects to report the tuple ('gamma',NULL) as  
the equal.  This is correct given SQL's treatment of NULL, and is  
easily fixed:

sqlite> select tableA.path, tableA.value from tableA,tableB where  
ifnull(tableA.path,'')=ifnull(tableB.path,'') and ifnull 
(tableA.value,'')=ifnull(tableB.value,'');
alpha|1
gamma|3
gamma|

However, the above statement has the unfortunate side effect of  
bypassing the index:

sqlite> explain select tableA.path, tableA.value from tableA,tableB  
where ifnull(tableA.path,'')=ifnull(tableB.path,'') and ifnull 
(tableA.value,'')=ifnull(tableB.value,'');
0|Goto|0|35|
1|Integer|0|0|
2|OpenRead|0|2|
3|SetNumColumns|0|2|
4|Integer|0|0|
5|OpenRead|1|4|
6|SetNumColumns|1|2|
7|Rewind|0|32|
8|Rewind|1|31|
9|Column|0|0|
10|String8|0|0|
11|CollSeq|0|0|collseq(BINARY)
12|Function|2|2|ifnull(2)
13|Column|1|0|
14|String8|0|0|
15|CollSeq|0|0|collseq(BINARY)
16|Function|2|2|ifnull(2)
17|Ne|28417|30|
18|Column|0|1|
19|String8|0|0|
20|CollSeq|0|0|collseq(BINARY)
21|Function|2|2|ifnull(2)
22|Column|1|1|
23|String8|0|0|
24|CollSeq|0|0|collseq(BINARY)
25|Function|2|2|ifnull(2)
26|Ne|28417|30|
27|Column|0|0|
28|Column|0|1|
29|Callback|2|0|
30|Next|1|9|
31|Next|0|8|
32|Close|0|0|
33|Close|1|0|
34|Halt|0|0|
35|Transaction|0|0|
36|VerifyCookie|0|4|
37|Goto|0|1|
38|Noop|0|0|



My question is:    Is there another way to write such a select  
statement which can solve both problems of treating NULL==NULL and  
using the index.

Thanks,
Sean



-----------------------------------------------------------------------------
To unsubscribe, send email to [EMAIL PROTECTED]
-----------------------------------------------------------------------------





-----------------------------------------------------------------------------
To unsubscribe, send email to [EMAIL PROTECTED]
-----------------------------------------------------------------------------

Reply via email to