我在这里有一种奇怪的行为,我希望有人可以向我解释.
我在查询中有两个字段.一个是通过拍摄转换为日期的数字字段to_date('01/01/1960', 'mm/dd/yyyy') + somethingorother.另一个是文本字段,其中包含至少一个非日期值,该值将转换为日期to_date(textField, 'mm/dd/rrrr').如果我运行查询,它运行正常.但是,如果我将查询括select * from ( ) where field1 > field2起来,则会出现"ORA-01861:文字与格式字符串不匹配"错误.如果我尝试排除拉回文本字段的子查询的where子句中的已知非日期值,则无效.
我知道没有代码几乎不可能搞清楚,但我想知道是否有人可以向我解释为什么没有过滤器它可以工作,但是当我添加它时会爆炸.谢谢.
一般的问题是,由于SQL是一种基于集合的语言,因此Oracle可以按照它选择的任何顺序自由地评估谓词.如果您有一个VARCAHR2存储某些日期值和一些非日期值的列,这意味着Oracle可以自由地评估首先过滤掉所有非日期值的谓词,或者评估检查是否有一个日期值的谓词转换后的DATE值大于另一个.如果在过滤掉非日期值之前恰好评估了DATE不等式谓词(field1 > field2),则会出现错误.  
SQL是基于集合的事实是使用错误数据类型是如此成问题的主要原因之一 - 您无法确定查询总是在调用转换之前过滤掉不可转换数据功能.即使你设置了像过滤掉无效数据的视图这样的抽象障碍,优化器也可以自由地重新排序谓词,这样你就可以很容易地发现你的查询最终会破坏你的抽象障碍,或者你有大多数时间都在运行的查询,除非优化器恰好选择不同的执行计划.Jonathan Gennick有一篇非常有趣的文章Subquery Madness,讨论了这个具体问题.
您可以编写自己的转换函数,忽略异常并在查询中使用它.例如,您可以创建一个函数
CREATE OR REPLACE FUNCTION my_to_date( p_date_str    IN VARCHAR2,
                                       p_format_mask IN VARCHAR2 )
  RETURN DATE
IS
  l_date DATE;
BEGIN
  l_date := to_date( p_date_Str, p_format_mask ); 
  RETURN l_date;
EXCEPTION
  WHEN OTHERS THEN
    RETURN null;
END;
Run Code Online (Sandbox Code Playgroud)
然后在查询中使用该函数
SELECT *
  FROM (SELECT to_date('01/01/1960', 'mm/dd/yyyy') + somethingorother field1,
               my_to_date( textField, 'mm/dd/rrrr' ) field2
          FROM your_table
         WHERE some_condition)
 WHERE field1 > field2
Run Code Online (Sandbox Code Playgroud)
这将起作用,因为调用my_to_date任何字符串都是有效的,无论它是否计算为有效,DATE因此您的查询不再取决于Oracle选择评估谓词的顺序.
|   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           4628 次  |  
        
|   最近记录:  |