【问题标题】:TO_DATE problemsTO_DATE 问题
【发布时间】:2012-02-22 19:50:34
【问题描述】:

我的 SQL where 子句中有以下内容。这是针对 Oracle 数据库运行的。 sc_dt 字段在 db 中定义为日期字段。

sc_dt = TO_DATE('2011-11-03 00:00:00.0', 'YYYY-MM-DD')

产生以下错误"date format picture ends before converting entire input string"

当我尝试使用以下内容计算小数秒(在本例中为 .0)时,我收到以下错误。

sc_dt = TO_DATE('2011-11-03 00:00:00.0', 'YYYY-MM-DD HH24:MI:SS.FF')

产生以下错误"date format not recognized"

我真的只是假设我需要.FF 来解释“来自”字符串中的.0。我还尝试了.FF1.FF2、...、.FF9,结果相同(此时我正抓着稻草)。

据我所知,sc_dt 字段始终填充月/日/年部分(而不是小时/分钟/秒部分)。

我正在调试一个 java 程序,该程序正在执行上述 SQL 作为带有 2011-11-03 00:00:00.0 值的准备好的语句。

我该如何解决这个问题?

【问题讨论】:

    标签: sql oracle to-date


    【解决方案1】:

    您需要使用午夜过后的秒数选项。比如:

    select TO_DATE('2011-11-03 00:00:01.1', 'YYYY-MM-DD HH24:MI:SS.SSSSS') from dual
    

    或者这个:

    select TO_TIMESTAMP('2011-11-03 00:00:00.1', 'YYYY-MM-DD HH24:MI:SS.FF') from dual
    

    【讨论】:

    • 你,好心的先生,摇滚。我应该在几个小时前问这个问题! (一旦堆栈溢出让我接受这个作为答案)。非常感谢!
    • 是的,.FF 仅适用于 TO_TIMESTAMP 函数而不适用于 TO_DATE。
    • 请注意,TO_DATE 调用仅在标识小数秒的字符串部分恰好也是自午夜以来的秒数(每小时仅可能发生 9 次)时才有效。如果您的时间总是在午夜,那可能不是问题。但总的来说,你会得到ORA-01838: seconds of minute conflicts with seconds in day 错误。如果 TO_TIMESTAMP 调用强制进行隐式强制转换以防止使用索引,则可能会导致性能问题。
    • 不,先生。只需将第一个示例更改为 '00:00:01.2'(任何 !=1 而不是 2)并查看失败。
    【解决方案2】:

    sc_dt 这样的Oracle DATE 列将始终包含日期和时间组件,一直到秒。根据您的查询工具及其配置方式(通常是会话的NLS_DATE_FORMAT),默认情况下可能不显示时间组件。但是,您可以通过显式 TO_CHAR 来查看时间组件

    SELECT to_char( sc_dt, 'YYYY-MM-DD HH24:MI:SS' ) 
      FROM table_name
    

    因为DATE 仅将时间存储到秒,但是,您不能在格式掩码中使用小数秒。所以你需要做这样的事情来提取字符串的一部分直到小数秒。如果您不能保证字符串总是在小数点前 19 个字符,您也可以使用 INSTR 来查找小数点并获取小数点之前的所有内容。

    TO_DATE( substr('2011-11-03 00:00:00.0', 1, 19), 'YYYY-MM-DD HH24:MI:SS')
    

    但是,由于这是来自 Java 应用程序,因此最好使用正确的数据类型。如果您在准备好的语句上使用setDate 方法而不是绑定字符串来绑定Java 日期(java.sql.Date),那么您不必在SQL 语句中处理字符串格式。

    【讨论】:

    • 我更喜欢 Justin 的 SUBSTR 解决方案,而不是其他使用 .SSSSS 格式模型的解决方案,这既是因为他在 cmets 中给出的其他答案的原因,也是因为更清楚的是时间的小数秒部分被丢弃。
    • @Justin - 谢谢你的解释!它可以帮助我理解我为什么要做我正在做的事情。
    • @Justin:不使用 setDate 的一个原因是 Java 和数据库之间发生的隐式时区转换。
    • @kevincline - 我不确定我是否理解。 Oracle DATE 没有关联的时区。 Java java.sql.Date 可以。 PreparedStatement 类的 setDate 方法使用 JVM 的默认时区或您传入的 Calendar 中指定的时区将 Java 日期转换为 Oracle 日期。无论哪种方式似乎都比丢弃时区信息更可取完全在传递给 Oracle 的刺痛中。
    • @Justin:java.sql.Date 没有时区。这是从 1970 年 1 月 1 日格林威治标准时间 00:00 开始的毫秒偏移量。 JVM 时区在全球范围内提供服务的系统上没有用处。并且数据库也有一个时区。这一切都令人难以置信的粘稠。见puretech.paawak.com/2010/11/02/…
    【解决方案3】:

    我知道这个帖子已经有一年多了,但是...... 将其放入的另一种选择可能是:

    src_dt=select TO_DATE('2011-11-03 00:00:01.1234', 'YYYY-MM-DD HH24:MI:SS.?????') from dual;
    

    注意:有一个额外的“?”扔进去是为了说明你甚至可以多加几个'?'。如果“?”表示的数字在源时间字符串中没有任何对应的字符,Oracle 不会提出任何投诉。如果您不确定收到的秒数精度,这可能会有所帮助。

    此选项为您的源时间的“小数秒”格式提供了一些灵活性。 我不知道这实际上在任何地方都有记录。

    【讨论】:

      【解决方案4】:

      我这样做了:

      ALTER SESSION 
      SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS.?';
      
      
      --Change the decimal
      ALTER SESSION 
      SET NLS_NUMERIC_CHARACTERS = ',.';
      

      它对我有用

      【讨论】:

        【解决方案5】:

        src_dt=select TO_DATE('2011-11-03 00:00:01.1', 'YYYY-MM-DD HH24:MI:SS.SSSSS') from dual

        如果您只需要日期输出,我想上面的应该可以工作。

        【讨论】:

        • 此 TO_DATE 调用仅在标识小数秒的字符串部分恰好也是自午夜以来的秒数(每小时仅可能发生 9 次)时才有效。如果您的时间总是在午夜,那可能不是问题。但一般来说,你会得到 ORA-01838: seconds of minute conflict with seconds in day 错误。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-31
        • 2014-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-28
        • 1970-01-01
        相关资源
        最近更新 更多