A date / null/ boolean logic idiosyncracy
David Wilson, May 13, 2010 - 11:38 am UTC
Hi Tom,
I do not understand why the first of the following 3 queries only selects four of the five records, while the following 2 select all five. The logic, superficially at least, seems to be the same for all. I suspect it has something to do with the fact that the date to be compared to is derived from a parameter table with an essentially untyped 'value' field even though I do explicitly use the to_date on the record I want to use.
TIA
David.
create table test_case (
job char(5),
id integer,
status char(1),
data1 varchar2(30),
data2 varchar2(30),
dated date,
processed_on date,
cancelled_on date,
corrects_job char(5),
corrects_id integer
);
insert into test_case
(job, id, status, data1, data2, dated, processed_on, cancelled_on,
corrects_job, corrects_id)
select 'aaaaa', 1, 'X', 'Hello', 'World', sysdate - (2*365 +10), sysdate - (2*365 +9), sysdate -(2*365 +8), null, null from dual
union
select 'aaaab', 1, 'X', 'Greetings', 'World', sysdate - (2*365 +8),sysdate - (2*365 +8), sysdate - (2*365 +7), 'aaaaa', 1 from dual
union
select 'aaaac', 1, 'X', 'Greetings', 'Earth', sysdate - (2*365 +7),sysdate - (2*365 +7), sysdate - (2*365 +6), 'aaaab', 1 from dual
union
select 'aaaad', 1, 'X', 'Goodbye', 'Earth', sysdate - (2*365 +6),sysdate - (2*365 +6), sysdate - (2*365 +5), 'aaaac', 1 from dual
union
select 'aaaae', 1, 'P', 'Goodbye', 'Cruel World', sysdate - (2*365 +5),sysdate - (2*365 +5), null, 'aaaad', 1 from dual
;
*/
/*
create table test_parameter
(
name varchar2(30),
value varchar2(240),
description varchar2(240)
);
insert into test_parameter
(name, value, description)
select 'CUTOFF_DATE', to_char(sysdate - (2*365), 'DD-MON-YYYY'), 'A cut-off date for selecting records old enough to be purged' from dual
union
select 'SLOGAN', 'HAVE a nice day :)', 'banal company slogan' from dual;
*/
Operating System Red Hat Enterprise Linux AS release 4 (Nahant Update 5) 2.6.9 55.0.9.ELsmp (64-bit)
Hardware Platform x86_64
sqlplus xxx/xxx@xxx
SQL*Plus: Release 10.2.0.2.0 - Production on Thu May 13 12:27:17 2010
Copyright (c) 1982, 2005, Oracle. All Rights Reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters, OLAP and Data Mining options
SQL> @test_case
SQL>
SQL> select
2 t.job,
3 t.id,
4 t.job || to_char(t.id) ji,
5 greatest(nvl(t.dated, nvl(t.processed_on, t.cancelled_on)), nvl(t.processed_on, nvl(t.cancelled_on, t.dated)), nvl(t.cancelled_on, nvl(t.dated, t.processed_on))) effective,
6 nvl(to_char(t.dated, 'DD-MON-YYYY'), '-'),
7 nvl(to_char(t.processed_on, 'DD-MON-YYYY'), '-'),
8 nvl(to_char(t.cancelled_on, 'DD-MON-YYYY'), '-'),
9 nvl(t.status, '-'),
10 t.data1,
11 t.data2,
12 t.corrects_job,
13 t.corrects_id,
14 t.corrects_job || to_char(t.corrects_id) cji,
15 to_char(p.acd, 'YYYYMMDD'),
16 LEVEL
17 from test_case t, (select to_date(value, 'DD-MON-YYYY') acd from test_parameter where name = 'CUTOFF_DATE') p
18 where
19 t.dated < p.acd
20 and
21 (
22 t.processed_on is null or
23 (
24 t.processed_on is not null
25 and t.processed_on < p.acd
26 )
27 )
28 and
29 (
30 t.cancelled_on is null or
31 (
32 t.cancelled_on is not null
33 and t.cancelled_on < p.acd
34 )
35 )
36 and
37 (
38 t.processed_on is not null or t.cancelled_on is not null
39 )
40 start with t.job = 'aaaaa' and t.id = 1
41 connect by prior t.job = t.corrects_job and t.corrects_id = prior t.id
42 ;
JOB ID JI EFFECTIVE NVL(TO_CHAR NVL(TO_CHAR NVL(TO_CHAR N DATA1 DATA2 CORRE CORRECTS_ID CJI TO_CHAR( LEVEL
----- ---------- --------------------------------------------- --------- ----------- ----------- ----------- - ------------------------------ ------------------------------ ----- ----------- --------------------------------------------- -------- ----------
aaaaa 1 aaaaa1 05-MAY-08 03-MAY-2008 04-MAY-2008 05-MAY-2008 X Hello World 20080513 1
aaaab 1 aaaab1 06-MAY-08 05-MAY-2008 05-MAY-2008 06-MAY-2008 X Greetings World aaaaa 1 aaaaa1 20080513 2
aaaac 1 aaaac1 07-MAY-08 06-MAY-2008 06-MAY-2008 07-MAY-2008 X Greetings Earth aaaab 1 aaaab1 20080513 3
aaaad 1 aaaad1 08-MAY-08 07-MAY-2008 07-MAY-2008 08-MAY-2008 X Goodbye Earth aaaac 1 aaaac1 20080513 4
4 rows selected.
SQL>
SQL>
SQL> select
2 t.job,
3 t.id,
4 t.job || to_char(t.id) ji,
5 greatest(nvl(t.dated, nvl(t.processed_on, t.cancelled_on)), nvl(t.processed_on, nvl(t.cancelled_on, t.dated)), nvl(t.cancelled_on, nvl(t.dated, t.processed_on))) effective,
6 nvl(to_char(t.dated, 'DD-MON-YYYY'), '-'),
7 nvl(to_char(t.processed_on, 'DD-MON-YYYY'), '-'),
8 nvl(to_char(t.cancelled_on, 'DD-MON-YYYY'), '-'),
9 nvl(t.status, '-'),
10 t.data1,
11 t.data2,
12 t.corrects_job,
13 t.corrects_id,
14 t.corrects_job || to_char(t.corrects_id) cji,
15 to_char(p.acd, 'YYYYMMDD'),
16 LEVEL
17 from test_case t, (select to_date(value, 'DD-MON-YYYY') acd from test_parameter where name = 'CUTOFF_DATE') p
18 where
19 t.dated < p.acd
20 and
21 (
22 t.processed_on is null or
23 (
24 t.processed_on is not null
25 and t.processed_on < p.acd
26 )
27 )
28 and
29 (
30 nvl(t.cancelled_on, p.acd -1) < p.acd
31 /*t.cancelled_on is null or
32 (
33 t.cancelled_on is not null
34 and t.cancelled_on < p.acd
35 ) */
36 )
37 and
38 (
39 t.processed_on is not null or t.cancelled_on is not null
40 )
41 start with t.job = 'aaaaa' and t.id = 1
42 connect by prior t.job = t.corrects_job and t.corrects_id = prior t.id
43 ;
JOB ID JI EFFECTIVE NVL(TO_CHAR NVL(TO_CHAR NVL(TO_CHAR N DATA1 DATA2 CORRE CORRECTS_ID CJI TO_CHAR( LEVEL
----- ---------- --------------------------------------------- --------- ----------- ----------- ----------- - ------------------------------ ------------------------------ ----- ----------- --------------------------------------------- -------- ----------
aaaaa 1 aaaaa1 05-MAY-08 03-MAY-2008 04-MAY-2008 05-MAY-2008 X Hello World 20080513 1
aaaab 1 aaaab1 06-MAY-08 05-MAY-2008 05-MAY-2008 06-MAY-2008 X Greetings World aaaaa 1 aaaaa1 20080513 2
aaaac 1 aaaac1 07-MAY-08 06-MAY-2008 06-MAY-2008 07-MAY-2008 X Greetings Earth aaaab 1 aaaab1 20080513 3
aaaad 1 aaaad1 08-MAY-08 07-MAY-2008 07-MAY-2008 08-MAY-2008 X Goodbye Earth aaaac 1 aaaac1 20080513 4
aaaae 1 aaaae1 08-MAY-08 08-MAY-2008 08-MAY-2008 - P Goodbye Cruel World aaaad 1 aaaad1 20080513 5
5 rows selected.
SQL>
SQL> select
2 t.job,
3 t.id,
4 t.job || to_char(t.id) ji,
5 greatest(nvl(t.dated, nvl(t.processed_on, t.cancelled_on)), nvl(t.processed_on, nvl(t.cancelled_on, t.dated)), nvl(t.cancelled_on, nvl(t.dated, t.processed_on))) effective,
6 nvl(to_char(t.dated, 'DD-MON-YYYY'), '-'),
7 nvl(to_char(t.processed_on, 'DD-MON-YYYY'), '-'),
8 nvl(to_char(t.cancelled_on, 'DD-MON-YYYY'), '-'),
9 nvl(t.status, '-'),
10 t.data1,
11 t.data2,
12 t.corrects_job,
13 t.corrects_id,
14 t.corrects_job || to_char(t.corrects_id) cji,
15 to_char(p.acd, 'YYYYMMDD'),
16 LEVEL
17 from test_case t, (select to_date(value, 'DD-MON-YYYY') acd from test_parameter where name = 'CUTOFF_DATE') p
18 where
19 t.dated < p.acd
20 and
21 (
22 t.processed_on is null or
23 (
24 t.processed_on is not null
25 and t.processed_on < p.acd
26 )
27 )
28 and
29 (
30 /*nvl(t.cancelled_on, p.acd -1) < p.acd */
31 t.cancelled_on is null or
32 (
33 t.cancelled_on is not null
34 and t.cancelled_on < sysdate - (2*365)
35 )
36 )
37 and
38 (
39 t.processed_on is not null or t.cancelled_on is not null
40 )
41 start with t.job = 'aaaaa' and t.id = 1
42 connect by prior t.job = t.corrects_job and t.corrects_id = prior t.id
43 ;
JOB ID JI EFFECTIVE NVL(TO_CHAR NVL(TO_CHAR NVL(TO_CHAR N DATA1 DATA2 CORRE CORRECTS_ID CJI TO_CHAR( LEVEL
----- ---------- --------------------------------------------- --------- ----------- ----------- ----------- - ------------------------------ ------------------------------ ----- ----------- --------------------------------------------- -------- ----------
aaaaa 1 aaaaa1 05-MAY-08 03-MAY-2008 04-MAY-2008 05-MAY-2008 X Hello World 20080513 1
aaaab 1 aaaab1 06-MAY-08 05-MAY-2008 05-MAY-2008 06-MAY-2008 X Greetings World aaaaa 1 aaaaa1 20080513 2
aaaac 1 aaaac1 07-MAY-08 06-MAY-2008 06-MAY-2008 07-MAY-2008 X Greetings Earth aaaab 1 aaaab1 20080513 3
aaaad 1 aaaad1 08-MAY-08 07-MAY-2008 07-MAY-2008 08-MAY-2008 X Goodbye Earth aaaac 1 aaaac1 20080513 4
aaaae 1 aaaae1 08-MAY-08 08-MAY-2008 08-MAY-2008 - P Goodbye Cruel World aaaad 1 aaaad1 20080513 5
5 rows selected.
SQL>
SQL>
SQL> spool off