转换 to_date 时为啥此查询不失败
Posted
技术标签:
【中文标题】转换 to_date 时为啥此查询不失败【英文标题】:Why doesn't this query fail, when converting to_date转换 to_date 时为什么此查询不失败 【发布时间】:2014-04-02 20:01:37 【问题描述】:此查询运行并且不返回任何行。
SELECT DISTINCT TO_CHAR(START_DATE,'MM/DD/YYYY'),
TO_CHAR(END_DATE, 'MM/DD/YYYY')
FROM
(
SELECT START_DATE, END_DATE, END_DATE - START_DATE
FROM
(
SELECT TO_DATE(SUBSTR(B, 1, 10), 'MM/DD/YYYY') START_DATE,
TO_DATE(SUBSTR(B, 14, 10), 'MM/DD/YYYY') END_DATE
FROM (SELECT 'test date' b from dual)
)
WHERE END_DATE - START_DATE != 6
)
由于转换错误,这个小片段无法运行。 [1]:ORA-01858:在需要数字的地方发现了一个非数字字符
SELECT TO_DATE(SUBSTR(B, 1, 10), 'MM/DD/YYYY') START_DATE,
TO_DATE(SUBSTR(B, 14, 10), 'MM/DD/YYYY') END_DATE
FROM (SELECT 'test date' b from dual)
我在这里的预期是转换错误会导致 Oracle 异常导致程序失败。有些事情我不知道,或者没有正确考虑。
有人能把我的鼻子指向正确的方向吗?
谢谢。 邪恶。
EDIT - NULL 与 to_date 的处理方式不同。 Oracle: Avoiding NULL value in to_date
编辑 - 计划
3 SELECT STATEMENT ALL_ROWS
Cost: 3 Bytes: 0 Cardinality: 1
Partition #: 0
2 FILTER
Cost: 0 Bytes: 0 Cardinality: 0
Partition #: 0
1 FAST DUAL
Cost: 2 Bytes: 0 Cardinality: 1
Partition #: 0
编辑 - 我正在运行 10g。
【问题讨论】:
!= 是 C,你的意思是 '测试日期'无效。 是的。这就是我把它放在那里的原因。预计完整查询会失败。 这很有趣。一定与优化器有关。 这就是为什么我总是告诉人们“检查实际查询的计划,包括绑定变量——不要只检查字面值”。 【参考方案1】:好的,我想通了,因为它让我发疯。如果您将查询简化为:
SELECT START_DATE, END_DATE, END_DATE - START_DATE
FROM
(
SELECT TO_DATE(SUBSTR(B, 1, 10), 'MM/DD/YYYY') START_DATE,
TO_DATE(SUBSTR(B, 14, 10), 'MM/DD/YYYY') END_DATE
FROM (SELECT 'test date' b from dual)
)
WHERE END_DATE - START_DATE != 6
生成的执行计划(在 11gR2 上)如下所示:
Execution Plan
----------------------------------------------------------
Plan hash value: 4034615273
-----------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |
|* 1 | FILTER | | | | |
| 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_DATE(NULL)-TO_DATE('test date','MM/DD/YYYY')<>6)
因此,CBO 已确定 END_DATE 的子字符串为空,因此,to_date 也将导致空值。然后优化器不会评估 START_DATE 表达式,并且不会遇到无效数据格式错误。如果执行,您可以看到相同的行为:
SELECT TO_DATE (NULL) - TO_DATE ('test date', 'MM/DD/YYYY') FROM DUAL
它不会失败。
【讨论】:
很好,+1。顺便说一句,如果输入一个大于 14 的字符串值,它将失败。以上是关于转换 to_date 时为啥此查询不失败的主要内容,如果未能解决你的问题,请参考以下文章
当具有相同术语的 HQL 选择有效时,为啥此 HQL 删除失败?
为啥我的 oracle to_date 返回此错误 ORA-01861: literal does not match format string