sql - 为什么这个查询在转换 to_date 时不会失败

标签 sql oracle select to-date

此查询运行但未返回任何行。

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 异常导致程序失败。有些事情我不知道,或者没有正确考虑。

谁能把我的 Nose 指向正确的方向?

谢谢。 邪恶。

编辑 - 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。

最佳答案

好吧,我想通了,因为它快把我逼疯了。如果您将查询简化为:

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

它不会失败。

关于sql - 为什么这个查询在转换 to_date 时不会失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22821795/

相关文章:

mysql - 将自动增量 ID 添加到现有表?

MySQL - 两个查询之间的区别

javascript - Jquery:设置基于 <select> 属性检查的 <option>

sql - 从查询中选择所有计数值

mysql - 查询多个表的公共(public)字段,然后按 1 个公共(public)字段排序

sql - 将事件表中的数据与事件发生之前更改日志表中的最新数据连接起来

sql - 为什么此 CREATE TABLE 语句会导致 "ORA-00922 missing or invalid option"?

database - OWB(Oracle Warehouse Builder)迁移助手遇到无效替换错误

sql - 如何选择具有 MAX(列值)的第一行?

带有变量的 Php mysql select 语句(无效参数编号 : number of bound variables does not match number of tokens)