我刚刚创建了一个包含以下数据的示例表:
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;
然后是以下查询,返回异常结果:(15条记录而不是7条)
select count(*) from aaa d
where
(d.dt > sysdate)
or
d.dt < to_date(20130120,'yyyymmdd')
但当我改变“OR”的左侧和右侧时,它返回正确的结果:(7条记录)
select count(*) from aaa d
where
d.dt < to_date(20130120,'yyyymmdd')
or
(d.dt > sysdate)
有人知道这个问题是什么以及如何解决它?
add:用d.dt + 1替换d.dt也解决了这个问题,
d.dt+1 > sysdate+1
答案 0 :(得分:3)
我能够复制它,这种行为背后的原因是Oracle对谓词的解释。
可以复制的操作系统和Oracle版本:
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>
在第一种情况下,谓词被修改为filter("D"."DT" IS NOT NULL)
而在第二个查询中,谓词的工作方式为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>
我无法弄清楚Oracle的这种行为,很可能有些专家可以解释这一点。
再次在第三个示例中,正确使用了谓词。 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>
很明显,Linux服务器上的Oracle版本11.2.0.2.0和11.2.0.3.0无法再现这些内容。
<强>更新强>
正如 Alex Poole 在评论中提到的 - “这可能是错误9495697,”对于在同一列上包含两个OR'd过滤谓词的查询,可能会返回错误的结果,其中另一方一个谓词不是编译时常量(例如,它是绑定,sysdate等等。)“