选择抛出ORA-01858异常

时间:2012-09-17 13:08:18

标签: sql oracle oracle10g

使用以下查询,将引发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'子句的所有行都是正确的格式。

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

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

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

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

我看到两种方法可以强制Oracle按您想要的顺序评估语句:

  1. 使用rownum。 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 hint

    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
    

答案 1 :(得分:0)

必须先评估TO_DATE子句,然后才能确定WHERE子句的真实性。如果您有在TO_DATE函数中无法评估的响应值,您将看到错误。

答案 2 :(得分: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需要一个数字。