如果您查看两个查询的执行计划,您可以看到优化器如何处理它们。对于第一个:
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TMPX | 1 | 6 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(LENGTH("TGL")=8 AND SUBSTR("TGL",5,2)>='01' AND
SUBSTR("TGL",5,2)<='12' AND TO_DATE("TGL",'YYYYMMDD')<TO_DATE('
1981-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
第二个:
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TMPX | 1 | 6 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(LENGTH("TGL")=8 AND TO_DATE("TGL",'YYYYMMDD')<TO_DATE('
1981-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
(SUBSTR("TGL",5,2)='01' OR SUBSTR("TGL",5,2)='02' OR
SUBSTR("TGL",5,2)='03' OR SUBSTR("TGL",5,2)='04' OR
SUBSTR("TGL",5,2)='05' OR SUBSTR("TGL",5,2)='06' OR
SUBSTR("TGL",5,2)='07' OR SUBSTR("TGL",5,2)='08' OR
SUBSTR("TGL",5,2)='09' OR SUBSTR("TGL",5,2)='10' OR
SUBSTR("TGL",5,2)='12'))
注意过滤器的应用顺序。在第一个中,它首先查看子字符串,只有通过该过滤器的值才会被转换为 1998 年比较的日期。
在第二个中,首先进行日期检查,因此它会在过滤掉无效值之前尝试转换它。
这里真正的问题是将日期存储为字符串,这允许输入无效数据。如果您对此感到困惑,那么另一种方法是使用函数尝试将字符串转换为日期并忽略引发的错误,这仍然不理想,但会忽略您已经存在的相同值。有很多这样的例子,including this one of mine。你可以这样做:
SELECT safe_to_date(tgl) tgl
FROM tmpx
WHERE safe_to_date(tgl) < date '1981-12-31';
或者如果您愿意:
SELECT tgl
FROM (
SELECT safe_to_date(tgl) tgl
FROM tmpx
)
WHERE tgl < date '1981-12-31';
您的函数只能查找 YYYYMMDD 格式字符串,或者如果您不希望它灵活,您可以传入要检查的格式。