日期检查以避免 sql 中的异常

Posted

技术标签:

【中文标题】日期检查以避免 sql 中的异常【英文标题】:date check to avoid exception in sql 【发布时间】:2013-02-05 04:47:35 【问题描述】:

我有一个查询,我需要将 TO_DATE(format specified is 'DD.MM.YYYY') 函数应用于 VARCHAR 类型列。但是,日期可能无效 例如'aa.12.2012' 或 '31.02.2012' 等

这将导致TO_DATE函数处理错误日期值时出现异常,查询将失败。

一种方法是运行光标并识别每个日期错误的单元格,但我想避免这种方式。

我尝试使用正则表达式,但我没有成功放置所有验证。

原来是这样


select
 case
   when regexp_like('24.01.2013',
                    '[[:digit:]]2.[[:digit:]]2.[[:digit:]]4') then
    1
   else
    0
 end chk
  from dual

这无法捕获像 2 月 31 日这样的无效日期。

是否可以在正则表达式中对日期进行所有验证,因为我通过 decode & case 执行了所有验证,而且相当冗长。


SELECT DECODE((REPLACE(TRANSLATE('29.01.2013', '0123456789.', ' '), ' ', '')),
              NULL,
              (CASE
                WHEN LENGTH('29.01.2013') != 10 THEN
                 'FALSE'
                WHEN LENGTH('29.01.2013') -
                     LENGTH(REPLACE(TRANSLATE('29.01.2013', '.', ' '),
                                    ' ',
                                    '')) != 2 THEN
                 'FALSE'
                WHEN INSTR('29.01.2013', '.', 1, 1) != 3 THEN
                 'FALSE'
                WHEN INSTR('29.01.2013', '.', 1, 2) != 6 THEN
                 'FALSE'
                WHEN TO_NUMBER(SUBSTR('29.01.2013', 4, 2)) IN
                     (1, 3, 5, 7, 8, 10, 12) THEN
                 (CASE
                WHEN TO_NUMBER(SUBSTR('29.01.2013', 1, 2)) >= 1 AND
                     TO_NUMBER(SUBSTR('29.01.2013', 1, 2)) <= 31 THEN
                 'TRUE'
                ELSE
                 'FALSE'
              END) WHEN
              TO_NUMBER(SUBSTR('29.01.2013', 4, 2)) IN (4, 6, 9, 11)
              THEN(CASE
                     WHEN TO_NUMBER(SUBSTR('29.01.2013', 1, 2)) >= 1 AND
                          TO_NUMBER(SUBSTR('29.01.2013', 1, 2)) <= 30 THEN
                      'TRUE'
                     ELSE
                      'FALSE'
                   END) WHEN TO_NUMBER(SUBSTR('29.01.2013', 4, 2)) IN (2)
              THEN(CASE
                     WHEN REMAINDER(TO_NUMBER(SUBSTR('29.01.2013', 7, 4)), 4) = 0 THEN
                      (CASE
                     WHEN TO_NUMBER(SUBSTR('29.01.2013', 1, 2)) >= 1 AND
                          TO_NUMBER(SUBSTR('29.01.2013', 1, 2)) <= 29 THEN
                      'TRUE'
                     ELSE
                      'FALSE'
                   END) WHEN
              REMAINDER(TO_NUMBER(SUBSTR('29.01.2013', 7, 4)), 4) != 0
              THEN(CASE
                     WHEN TO_NUMBER(SUBSTR('29.01.2013', 1, 2)) >= 1 AND
                          TO_NUMBER(SUBSTR('29.01.2013', 1, 2)) <= 28 THEN
                      'TRUE'
                     ELSE
                      'FALSE'
                   END) END) END), 'FALSE')
  FROM DUAL

提前致谢

【问题讨论】:

为什么首先将DATE 存储在VARCHAR 列中。如果你使用正确的数据类型,那么你就不需要这样的杂牌 公平点,但是我将 excel 中的值(不检查)转储到该字段中。如果出现日期格式错误,我需要准确识别和报告,否则将使用有效日期 【参考方案1】:

以下正则表达式验证日期:

^(((?=\d2\.(0[13578]|1[02]))(0[1-9]|[12]\d|3[01]))|((?=\d2\.(0[469]|11))(0[1-9]|[12]\d|30))|((?=\d2\.02\.\d2([02468][048]|[13579][26]))(0[1-9]|[12]\d))|(((?=\d2\.02\.\d2([02468][^048]|[13579][^26]))(0[1-9]|1\d|2[0-8]))))\.(0[1-9]|1[0-2])\.(03[1-9]|((?!03\d)\d4))$

注意:会有一个使用条件表达式的更简单的正则表达式。

【讨论】:

【参考方案2】:

在这种情况下,我永远无法让正则表达式完全正常工作——99% 的情况下都可以,但像闰年这样的事情总是很困难。

我之前在网上看到过这个似乎效果很好:

CREATE OR REPLACE FUNCTION MY2DATE (p_str IN VARCHAR2
  ,format_picture IN VARCHAR2
)
   RETURN DATE
IS
BEGIN
   RETURN TO_DATE(p_str, format_picture);
EXCEPTION
   WHEN OTHERS
   THEN
      RETURN NULL;
END;
/

基本上,传递字符串值和格式,如果捕获到任何异常,它将返回 NULL。

祝你好运。

【讨论】:

我已经这样做了,但我希望这需要一个程序。我想编写一个避免无效日期的查询。像 IS NULL 这样的东西,它成功地避免了 NULL 值行。我只想避免无效日期

以上是关于日期检查以避免 sql 中的异常的主要内容,如果未能解决你的问题,请参考以下文章

在java中,String转换Date日期类型容易出现时间转换异常,如何避免!

避免个别行在 Pig 中的 ToDate 中出现异常

如何检查数组元素是不是为空以避免Java中的NullPointerException

Sonarqube - 避免捕获通用异常

OnCreate 中的 AsyncTask 在运行时失败,如何在 Android 中避免这种情况?

如何避免 SQL 查询检查 IS NULL 的误报?