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

发布于 2024-09-06 11:19:18 字数 1547 浏览 6 评论 0原文

来自 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 执行 date BETWEEN 查询,以便选择日期范围。

Dear SQL Gurus from Stack Overflow:

Environment: Oracle

I'm trying to understand why I can't do a to_date selection on a table column that contains strings. Note tableZ with a column of name Value in the example below contains a bunch of strings, some of which are the correct format, for example 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 |

The following works

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

This returns something like (which is good):

| somedate            |
| __________________  |
| 21.06.2010 00:00:00 |
| 21.06.2010 00:00:00 |
| 22.06.2010 00:00:00 |

The following does not work

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

Comes back with:

ORA-01861: literal does not match format string

What am I missing here? Just a quick note:

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

doesn't work either.

Thanks!!

Goal to be able to do date BETWEEN queries on c.value in order to select date ranges.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

眼中杀气 2024-09-13 11:19:18

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

The order that Oracle evaluates the conditions found in the where clause is not fixed. That is to say that it can choose to evaluate the condition containing TO_DATE before the other criteria, in which case the query will fail. To prevent that, add the ordered_predicates hint to your query, but be aware that this may require additional manual tuning to improve performance.

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

Apparently ordered_predicates is deprecated starting with 10g. In that case, I think your only option is to use a sub-query in such a way that optimizer is forced to evaluate it first (i.e. it can't combine the queries). The easiest way to do this is to put rownum in the where statement of the inner query.

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
撑一把青伞 2024-09-13 11:19:18

另一种技术是将转换嵌入到 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)

,当子句很复杂时,这会变得非常难看。

Another technique is embed the conversion in a CASE.
For example

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

This gets REALLY ugly fast when the clauses are complicated though.

春花秋月 2024-09-13 11:19:18
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
-------------------
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;
/

Testing:

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
-------------------
难得心□动 2024-09-13 11:19:18

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

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

?这是行不通的,您需要以其他方式执行检查。您可以使用正则表达式(我猜,有一段时间没有使用它们了)。如果您的数据模型允许您识别有问题的行,那就更好了。

Do you want to check if c.value is a valid format with

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

? This wont work, you will need to perform the check in some other way. You could use a regular expression (i guess, not used them in a while). Better yet if your data model would allow you to discern the rows in question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文