问题
I've just created a sample table with following data:
CREATE TABLE AAA ( DT DATE );
insert into aaa (DT) values (to_date('13-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('14-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('15-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('16-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('17-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('18-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('19-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('20-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('21-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('22-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('23-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('24-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('25-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('26-01-2013', 'dd-mm-yyyy'));
insert into aaa (DT) values (to_date('27-01-2013', 'dd-mm-yyyy'));
commit;
and then the following query, returns abnormal results: (15 records instead of 7)
select count(*) from aaa d
where
(d.dt > sysdate)
or
d.dt < to_date(20130120,'yyyymmdd')
but when I change left side and right side of "OR" it returns correct result: (7 records)
select count(*) from aaa d
where
d.dt < to_date(20130120,'yyyymmdd')
or
(d.dt > sysdate)
does anybody know what is this issue about and how to solve it?
add: replacing d.dt with d.dt+1 is also solving this problem,
d.dt+1 > sysdate+1
回答1:
Well I am able to replicate it and the reason behind such behavior is Oracle's interpretation of predicates.
Version of OS and Oracle where this can be reproduced:
SQL> host ver
Microsoft Windows [Version 6.1.7601]
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for 64-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
SQL>
In the first case predicate is modified to filter("D"."DT" IS NOT NULL)
while in the second query, predicate works as provided filter("D"."DT"<TO_DATE(' 2013-01-20 00:00:00', 'syyyy-mm-dd hh24:mi:ss') OR "D"."DT">SYSDATE@!)
SQL> select count(*)
2 from aaa d
3 where (d.dt > sysdate)
4 or d.dt < to_date('20130120','yyyymmdd')
5 /
COUNT(*)
----------
15
Execution Plan
----------------------------------------------------------
Plan hash value: 977873394
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| AAA | 15 | 135 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("D"."DT" IS NOT NULL)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
346 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> ed
Wrote file afiedt.buf
1 select count(*)
2 from aaa d
3 where d.dt < to_date('20130120','yyyymmdd')
4* or (d.dt > sysdate)
SQL>
/
COUNT(*)
----------
7
Execution Plan
----------------------------------------------------------
Plan hash value: 977873394
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| AAA | 7 | 63 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("D"."DT"<TO_DATE(' 2013-01-20 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') OR "D"."DT">SYSDATE@!)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
4 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
346 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
I could not figure out this behavior of Oracle, quite possible some experts can explain this.
Again in the third example, predicates are used correctly. filter("D"."DT"<TO_DATE(' 2013-01-20 00:00:00', 'syyyy-mm-dd hh24:mi:ss') OR INTERNAL_FUNCTION("D"."DT")+1>SYSDATE@!+1)
SQL> ed
Wrote file afiedt.buf
1 select count(*)
2 from aaa d
3 where (d.dt + 1 > sysdate + 1)
4* or d.dt < to_date('20130120','yyyymmdd')
SQL> /
COUNT(*)
----------
7
Execution Plan
----------------------------------------------------------
Plan hash value: 977873394
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 9 | | |
|* 2 | TABLE ACCESS FULL| AAA | 7 | 63 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("D"."DT"<TO_DATE(' 2013-01-20 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') OR INTERNAL_FUNCTION("D"."DT")+1>SYSDATE@!+1)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
5 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
346 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
Its quite obvious that the same cannot be reproduced from Oracle Version 11.2.0.2.0 and 11.2.0.3.0 on Linux servers.
Update:
As Alex Poole mentioned in the comments - "This might be bug 9495697, 'Wrong results may be returned for a query containing two OR'd filter predicates on the same column, where the other side of one predicate is not a compile-time constant (eg. It is a bind, sysdate, etc..)"
来源:https://stackoverflow.com/questions/21076649/using-or-in-where-clause-for-date-type-column-issue-when-compare-with-sysdate