【问题标题】:Oracle TO_DATE NOT throwing errorOracle TO_DATE NOT 抛出错误
【发布时间】:2016-04-17 02:28:08
【问题描述】:

我刚刚发现 oracle TO_DATE 函数与 format_mask 参数一起使用时的奇怪行为。

基本上,我看到的是,在一种情况下,它会忽略给定的格式掩码,并使用自己的掩码解析输入,而在其他情况下,它会引发异常。

示例 I 预期行为 - 抛出错误:

SELECT TO_DATE('18-02-2016', 'DD/MON/YYYY') FROM dual

ORA-01843: 月份无效

示例 II 意外行为 - 解析日期:

SELECT TO_DATE('18-feb-2016', 'DD/MM/YYYY') FROM dual

2016 年 2 月 18 日 00:00:00

我在文档中看不到这方面的任何评论,所以我想知道这种不合时宜的做法是设计使然,还是错误,或者我没有理解正确的东西?

编辑: 查看答案,我同意这很可能是设计使然。但是这里所做的对我来说看起来危险地“自动”。

如果格式将被错误地解释(被 oracle 猜测)怎么办?有没有关于这里到底发生了什么的文档,所以我可以确定它是安全的?

我的问题是——我可以把它关掉吗?我唯一的选择是自己验证格式吗?

【问题讨论】:

  • 我冒昧地运行了 sn-ps 并编辑了问题以包含实际输出。我认为您得到“ORA-01843:不是有效月份”而不是“ORA-01830:日期格式图片在转换整个输入字符串之前结束”或其他内容可能相关。

标签: sql oracle oracle12c


【解决方案1】:

这是设计使然。即使不符合定义的掩码,Oracle 也会尝试在字符串中找到确定的日期表示。它只会抛出错误,只是它没有找到确定的日期或日期的某些必需组件丢失或未解决。

【讨论】:

  • deterministic date representation 到底是什么以及它是如何工作的?我在哪里可以找到它的描述?更重要的是——我怎样才能把它关掉?另外,如果您考虑我的示例,您会发现在这两种情况下,Oracle 都有完全相同的信息来识别真实格式,并且在这两种情况下,它都能正确地做到这一点。
  • 在指定精确掩码时将其关闭:'FX'。我实际上是在使用确定性,因为TO_DATE('2016111', 'YYYYMMDD') 不是确定性的,我可能是 2016-11-01 或 2016-01-11,Oracle 更喜欢第一个元素,因此它是 2016-11-01。
【解决方案2】:

我认为02 可以表示日期/月份/年份任何内容,但feb 仅表示一件事,month。 我还在11g 中交叉检查了相同的内容,并得到了与12c 中相同的输出。所以它必须是由oracle设计的。

【讨论】:

  • 是的,但是SELECT TO_DATE('feb-08-2016', 'DD/MM/YYYY') FROM dual 失败了,对吧?我将更新我的问题,使其更具体。
  • 这给出了错误,但 SELECT TO_DATE('feb-08-2016', 'MM/DD/YYYY') FROM dual; 没有。所以必须是设计
【解决方案3】:

请看这里的表格:https://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements004.htm#g195479

它是日期时间格式模型的字符串到日期转换规则部分的一部分。在MM 的情况下,如果没有匹配,它会尝试MONMONTH。同样,如果您指定MON,但它没有找到,它会尝试MONTH。如果您指定MONTH,但它找不到它,它会尝试MON,但它永远不会尝试MM,除了MM

回答问题:Can I turn it off? 答案是,是的。

您可以通过在格式中指定 FX 来做到这一点。

SELECT TO_DATE('18/february/2016', 'FXDD/MM/YYYY') FROM dual;

现在返回:

[错误] 执行 (4: 16): ORA-01858: 一个非数字字符 找到了应该是数字的地方

鉴于以下情况:

SELECT TO_DATE('18/02/2016', 'FXDD/MM/YYYY') FROM dual;

返回预期:

2016 年 2 月 18 日

请注意,在指定 FX 时,您必须使用正确的分隔符,否则会出错。

【讨论】:

  • 正是我需要的,谢谢。另外,答案在我在问题中链接的页面上。 o.O 我真的应该把它读到最后。
  • 不用担心,这是一个相当小的部分,位于一个大文档的末尾。 =)
【解决方案4】:

如果您想禁止 Oracle 尝试提供帮助并解释不完全匹配的内容,您可以使用the FX format modifier

外汇
格式准确。此修饰符指定 TO_DATE 函数的字符参数和日期时间格式模型的精确匹配:

  • 字符参数中的标点和引用文本必须与格式模型的相应部分完全匹配(大小写除外)。
  • 字符参数不能有多余的空格。如果没有 FX,Oracle 会忽略多余的空格。
  • 字符参数中的数字数据必须与格式模型中的相应元素具有相同的位数。如果没有 FX,字符参数中的数字可以省略前导零。
  • 启用 FX 后,您也可以使用 FM 修饰符禁用此前导零检查。

所以你的例子会出错:

SELECT TO_DATE('18-feb-2016', 'FXDD/MM/YYYY') FROM dual;

SQL Error: ORA-01858: a non-numeric character was found where a numeric was expected

这也需要分隔符完全匹配:

SELECT TO_DATE('18-02-2016', 'FXDD/MM/YYYY') FROM dual;

SQL Error: ORA-01861: literal does not match format string

如果你做对了,那没关系:

SELECT TO_DATE('18/02/2016', 'FXDD/MM/YYYY') FROM dual;
SELECT TO_DATE('18-feb-2016', 'FXDD-MON-YYYY') FROM dual;

它没有抱怨第二个示例中的不同情况。但如果你省略前导零,它会报错;

SELECT TO_DATE('18/2/2016', 'FXDD/MM/YYYY') FROM dual;

SQL Error: ORA-01862: the numeric value does not match the length of the format item

...除非您包含 FM 修饰符:

SELECT TO_DATE('18/2/2016', 'FMFXDD/MM/YYYY') FROM dual;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-01
    • 2022-06-16
    • 2018-12-29
    • 2012-09-05
    • 2014-11-12
    • 2021-06-18
    • 2019-07-23
    相关资源
    最近更新 更多