来自Stack Overflow的亲爱的SQL专家:
环境: Oracle
我试图理解为什么我不能对包含字符串的表列进行to_date选择。注意下面示例中带有名称值Value的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
这会返回类似的东西(很好):
| somedate |
| __________________ |
| 21.06.2010 00:00:00 |
| 21.06.2010 00:00:00 |
| 22.06.2010 00:00:00 |
以下内容不起作用
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上对BETWEEN进行日期查询,以便选择日期范围。
答案 0 :(得分:9)
Oracle评估where子句中找到的条件的顺序不固定。也就是说,它可以选择在其他条件之前评估包含TO_DATE的条件,在这种情况下查询将失败。为了防止这种情况,请将ordered_predicates提示添加到您的查询中,但请注意,这可能需要额外的手动调整以提高性能。
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
显然,从10g开始,不推荐使用ordered_predicates
。在这种情况下,我认为您唯一的选择是使用子查询,以便优化器首先被强制评估它(即它不能组合查询)。最简单的方法是将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
答案 1 :(得分:1)
create or replace function to_date_or_null(v_str_date in varchar2
, v_str_fmt in varchar2 default null) return date as
begin
if v_str_fmt is null then
return to_date(v_str_date);
else
return to_date(v_str_date, v_str_fmt);
end if;
exception
when others then
return null;
end to_date_or_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
-------------------
答案 2 :(得分:1)
另一种技术是将转换嵌入CASE中。 例如
SELECT * FROM table
WHERE col_a = '1'
AND case when col_a = '1' then to_date(col_b,'DD/MM/YYYY') end = trunc(sysdate)
但是当条款复杂时,这很快就会变得非常丑陋。
答案 3 :(得分:0)
是否要检查c.value是否为
的有效格式AND To_Date(c.Value, 'DD.MM.YYYY HH24:MI:SS') IS NOT NULL
?这不会起作用,您需要以其他方式执行检查。你可以使用正则表达式(我想,暂时不使用它们)。更好的是,如果您的数据模型允许您识别有问题的行。