文字与字符串列上Oracle SQL to_date的格式字符串不匹配

文字与字符串列上Oracle SQL to_date的格式字符串不匹配,sql,oracle,datetime,to-date,Sql,Oracle,Datetime,To Date,亲爱的来自堆栈溢出的SQL专家: 环境:Oracle 我试图理解为什么不能在包含字符串的表列上选择截止日期。注意:下例中带有名称值列的tableZ包含一组字符串,其中一些是正确的格式,例如6/20/2010 00:00:00 tableZ | Value | | __________________ | | 6/21/2010 00:00:00 | | Somestring | | Some Other strings | | 6/21/2010 00:

亲爱的来自堆栈溢出的SQL专家:

环境:Oracle

我试图理解为什么不能在包含字符串的表列上选择截止日期。注意:下例中带有名称值列的tableZ包含一组字符串,其中一些是正确的格式,例如6/20/2010 00:00:00

tableZ

| Value              |
| __________________ |
| 6/21/2010 00:00:00 |
| Somestring         |
| Some Other strings |
| 6/21/2010 00:00:00 |
| 6/22/2010 00:00:00 |
以下作品

SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate 
          FROM tableX a, tableY b, tableZ c 
         WHERE Lower(a.name) = 'somedate' 
           AND a.id = b.other_id 
           AND b.id = c.new_id
这将返回类似(这很好)的结果:

以下操作不起作用

SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate 
          FROM properties$aud a, template_properties$aud b, consumable_properties$aud c 
         WHERE Lower(a.name) = 'somedate' 
           AND a.id = b.property_id 
           AND b.id = c.template_property_id 
           AND To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
带着:

ORA-01861:文字与格式字符串不匹配

我错过了什么?只需简单说明一下:

 ...
AND b.id = c.template_property_id 
AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
也不行

谢谢


目标能够在查询c.value之间进行日期选择,以选择日期范围。

是否检查c.value是否为有效的格式

AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL

??这不起作用,您需要以其他方式执行检查。你可以使用正则表达式(我想,暂时不用了)。如果您的数据模型允许您识别有问题的行,则更好。

Oracle评估where子句中的条件的顺序是不固定的。也就是说,它可以选择在其他条件之前评估包含to_DATE的条件,在这种情况下,查询将失败。为了防止出现这种情况,请向查询中添加ordered_谓词提示,但请注意,这可能需要额外的手动调优来提高性能

SELECT /*+ ordered_predicates */
               To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate 
          FROM properties$aud a, 
               template_properties$aud b, 
               consumable_properties$aud c 
         WHERE Lower(a.name) = 'somedate' 
           AND a.id = b.property_id 
           AND b.id = c.template_property_id 
           AND To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL

显然,
ordered_谓词
从10g开始就不推荐使用。在这种情况下,我认为您唯一的选择是使用子查询,使优化器必须首先对其求值(即,它不能组合查询)。最简单的方法是将
rownum
放在内部查询的where语句中

SELECT To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') somedate 
  FROM (SELECT value 
          FROM properties$aud a, 
               template_properties$aud b, 
               consumable_properties$aud c 
         WHERE Lower(a.name) = 'somedate' 
           AND a.id = b.property_id 
           AND b.id = c.template_property_id
           AND rownum > 0) 
 WHERE To_Date(c.Value, 'MM/DD/YYYY HH24:MI:SS') IS NOT NULL
测试:

SQL> select to_date_or_null('2000-01-01', 'YYYY-MM-DD') from dual -- Valid;

TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00

SQL> select to_date_or_null('Not a date at all') from dual -- Not Valid;

TO_DATE_OR_NULL('NO
-------------------


SQL> select to_date_or_null('2000-01-01') from dual -- Valid matches my NLS settings;

TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00

SQL> select to_date_or_null('01-Jan-00') from dual -- Does not match my NLS settings;

TO_DATE_OR_NULL('01
-------------------

另一种技术是将转换嵌入案例中。 比如说

SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)

但是,当子句很复杂时,这种情况很快就会变得很糟糕。

不,如上所述,我的目标是在查询之间进行切换,以便选择日期范围。IS NOT NULL对我来说只是一种检查查询是否有效的简单方法,oracle错误表明并非如此。这是一个好主意,但我没有让它用于初始测试?@Rio,如果你需要更多帮助,说“我没有让它工作”是不够的。他的评论只是回应了有序的_谓词部分。其余的都是在我研究它为什么不起作用时加上的…谢谢你,艾伦。这个答案很有价值,希望也能启发其他人!据我所知,Oracle优化器有时会将谓词推送到内嵌视图中,导致对无效值触发to_date和to_number,即使内嵌视图应该过滤掉它们。在这种情况下,这是不幸的。看到和
SQL> select to_date_or_null('2000-01-01', 'YYYY-MM-DD') from dual -- Valid;

TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00

SQL> select to_date_or_null('Not a date at all') from dual -- Not Valid;

TO_DATE_OR_NULL('NO
-------------------


SQL> select to_date_or_null('2000-01-01') from dual -- Valid matches my NLS settings;

TO_DATE_OR_NULL('20
-------------------
2000-01-01 00:00:00

SQL> select to_date_or_null('01-Jan-00') from dual -- Does not match my NLS settings;

TO_DATE_OR_NULL('01
-------------------
SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)