Oracle TO_DATE 不抛出错误

Oracle TO_DATE NOT throwing error

我刚刚发现了 oracle TO_DATE function when used with format_mask 参数的奇怪行为。

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

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

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

ORA-01843: not a valid month

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

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

February, 18 2016 00:00:00

我在文档中看不到任何关于此的评论,所以我想知道这种不一致是设计使然还是错误,或者我可能没有理解正确的东西?

编辑: 查看答案我可以同意这很可能是设计使然。但是这里所做的事情在我看来 "automagical" 很危险。

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

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

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

我认为 02 可以表示 date/month/year 任何东西,但是 feb 只表示一件事,month。 此外,我在 11g 中进行了相同的交叉检查,并得到了与你在 12c 中相同的输出。所以它必须由 oracle 设计。

请参阅此处的 table:https://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements004.htm#g195479

它是日期时间格式模型的 String-To-Date 转换规则部分的一部分。在 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;

现在returns:

[Error] Execution (4: 16): ORA-01858: a non-numeric character was found where a numeric was expected

鉴于以下内容:

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

Returns 预期:

2/18/2016

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

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

FX
Format exact. This modifier specifies exact matching for the character argument and datetime format model of a TO_DATE function:

  • Punctuation and quoted text in the character argument must exactly match (except for case) the corresponding parts of the format model.
  • The character argument cannot have extra blanks. Without FX, Oracle ignores extra blanks.
  • Numeric data in the character argument must have the same number of digits as the corresponding element in the format model. Without FX, numbers in the character argument can omit leading zeros.
  • When FX is enabled, you can disable this check for leading zeros by using the FM modifier as well.

所以你的例子会出错:

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;