0

使用以下查询,将引发 Oracle 异常。但是,我不明白为什么。任何人都可以解释一下吗?

select visit_id, to_date(response, 'DD/MM/YYYY') as convertedDate from 
(
select *
from dat_results_ext
where item_name = 'CALLBACKDATE'
)
where to_date(response, 'DD/MM/YYYY')  > sysdate

我理解这个例外意味着它试图转换“响应”字段,但它遇到了一个非数字。问题是它应该带回的行具有正确格式的所有内容。

'response' 字段是一个 varchar 字段,但所有以 'item_name = 'CALLBACKDATE' 子句返回的行都是正确的格式。

有任何想法吗?

4

3 回答 3

2

优化器可以在尝试找到最佳执行计划之前重写您的查询。在您的情况下,由于您没有阻止优化器执行此操作的提示,它可能会取消您的子查询并将您的查询重写为:

SELECT *
  FROM dat_results_ext
 WHERE item_name = 'CALLBACKDATE'
   AND to_date(response, 'DD/MM/YYYY') > sysdate

您无法控制 WHERE 子句中语句的评估顺序,因此 Oracle 可能to_date首先在不可转换为日期的行上评估函数,因此出现错误。

我看到两个选项可以强制 Oracle 按您想要的顺序评估语句:

  1. 使用行号。Rownum 将实现子查询,防止 Oracle 将其与外部查询合并:

    SELECT visit_id, to_date(response, 'DD/MM/YYYY') AS convertedDate
      FROM (SELECT r.*, 
                   rownum /* will materialize the subquery */
              FROM dat_results_ext r
             WHERE item_name = 'CALLBACKDATE')
     WHERE to_date(response, 'DD/MM/YYYY') > sysdate
    
  2. 使用NO_MERGE提示

    SELECT visit_id, to_date(response, 'DD/MM/YYYY') AS convertedDate
      FROM (SELECT /*+ NO_MERGE */ *
              FROM dat_results_ext
             WHERE item_name = 'CALLBACKDATE')
     WHERE to_date(response, 'DD/MM/YYYY') > sysdate
    
于 2012-09-17T13:53:29.577 回答
0

The TO_DATE clause has to be evaluated before the truth of the WHERE clause can be determined. If you have values of response that can't be evaluated in the TO_DATE function, you'll see the error.

于 2012-09-17T13:26:15.617 回答
0

准确地说,这是因为 的某些值response与 的格式掩码不匹配造成的DD/MM/YYYY。例如,如果您的会话设置为默认日期格式DD-MON-YY,请执行以下操作,您将收到错误消息:-

select to_date('17/SEP/2012','DD/MM/YYYY') from dual;
ERROR:
ORA-01858: a non-numeric character was found where a numeric was expected

由于您在月份字段中传递了一个字符,而 Oracle 需要一个数字。

于 2012-09-17T13:32:11.020 回答