using “or” in where clause for date type column issue when compare with sysdate in Oracle

痞子三分冷 提交于 2019-12-11 13:29:14

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!