【问题标题】:Filter out records that are not in this date format oracle过滤掉不是这个日期格式的记录oracle
【发布时间】:2020-11-02 20:25:51
【问题描述】:

如何过滤只能使用to_date('31-May-2019 00:00:00', 'DD-MON-YYYY HH24:MI:SS')转换为日期的记录

WITH dates   AS (
SELECT '0201-05-31 00:00:00' dates_col FROM dual UNION ALL
SELECT '31-May-2019 00:00:00' FROM dual UNION ALL
SELECT 'TEXT' FROM dual UNION ALL
SELECT '15-May-2019 00:00:00' FROM dual UNION ALL
SELECT '01-Apr-2019 00:00:00' FROM dual UNION ALL
SELECT '01-Apr-2019' FROM dual 
) SELECT * FROM dates  WHERE dates_col = ???

来自上面的示例查询 我期待下面的结果

31-May-2019 00:00:00
15-May-2019 00:00:00
01-Apr-2019 00:00:00
01-Apr-2019

我如何在 oracle 中实现这一点。

我想这样做的原因:我正在接收原始数据并将其加载到表中,然后再清理它们以将干净的数据插入到最终表中。

【问题讨论】:

    标签: sql regex oracle


    【解决方案1】:

    您可以使用内联函数来检查日期是否有效。像这样:

    WITH 
    FUNCTION is_valid_date (date_str_i VARCHAR2, format_i VARCHAR2) RETURN VARCHAR2
    /* check if date is valid */
    AS
      l_dummy_dt DATE;
    BEGIN
      SELECT TO_DATE(date_str_i,format_i) INTO l_dummy_dt FROM DUAL;
      RETURN 'Y';
    EXCEPTION WHEN OTHERS THEN
      RETURN 'N';
    END; 
    dates  AS (
    SELECT '0201-05-31 00:00:00' dates_col FROM dual UNION ALL
    SELECT '31-May-2019 00:00:00' FROM dual UNION ALL
    SELECT 'TEXT' FROM dual UNION ALL
    SELECT '15-May-2019 00:00:00' FROM dual UNION ALL
    SELECT '01-Apr-2019 00:00:00' FROM dual UNION ALL
    SELECT '01-Apr-2019' FROM dual 
    ) SELECT *
      FROM dates
     WHERE is_valid_date(dates_col,'DD-MON-YYYY HH24:MI:SS') = 'Y';
    
    

    【讨论】:

      【解决方案2】:

      啊,好老 VARCHAR2 约会...以及随之而来的欢乐。

      一种选择是创建一个函数来尝试将这些值转换为日期。如果成功 - 很好,没关系。否则,它不是。例如:

      SQL> create or replace function f_datum_ok_01 (par_datum in varchar2) return number
        2  is
        3    l_datum date;
        4  begin
        5    l_datum := to_date(par_datum,
        6                       'dd-mon-yyyy hh24:mi:ss',
        7                       'nls_date_language = english');
        8    return 1;
        9  exception
       10    when others then
       11      return 0;
       12  end f_datum_ok_01;
       13  /
      
      Function created.
      

      测试:

      SQL> select datum, f_datum_ok_01(datum) from test;
      
      DATUM                          F_DATUM_OK_01(DATUM)
      ------------------------------ --------------------
      0201-05-31 00:00:00                               0
      31-May-2019 00:00:00                              1
      TEXT                                              0
      15-May-2019 00:00:00                              1
      01-Apr-2019 00:00:00                              1
      01-Apr-2019                                       1
      
      6 rows selected.
      
      SQL>
      

      函数返回1 的行是可接受的。

      • 缺点:对于大量数据(上下文切换)可能会很慢。
      • 好处:您可以添加其他有效格式并接受这些值。

      【讨论】:

        【解决方案3】:

        从 Oracle 12.2 开始,您可以使用特殊功能 VALIDATE_CONVERSION:https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/VALIDATE_CONVERSION.html#GUID-DC485EEB-CB6D-42EF-97AA-4487884CB2CD

        SELECT VALIDATE_CONVERSION(1000 AS BINARY_DOUBLE)
          FROM DUAL;
        
        SELECT VALIDATE_CONVERSION('1234.56' AS BINARY_FLOAT)
          FROM DUAL;
        
        SELECT VALIDATE_CONVERSION('July 20, 1969, 20:18' AS DATE,
            'Month dd, YYYY, HH24:MI', 'NLS_DATE_LANGUAGE = American')
          FROM DUAL;
        
        SELECT VALIDATE_CONVERSION('200 00:00:00' AS INTERVAL DAY TO SECOND)
          FROM DUAL;
        
        SELECT VALIDATE_CONVERSION('P1Y2M' AS INTERVAL YEAR TO MONTH)
          FROM DUAL;
        
        SELECT VALIDATE_CONVERSION('$100,00' AS NUMBER,
            '$999D99', 'NLS_NUMERIC_CHARACTERS = '',.''')
          FROM DUAL;
        
        SELECT VALIDATE_CONVERSION('29-Jan-02 17:24:00' AS TIMESTAMP,
            'DD-MON-YY HH24:MI:SS')
          FROM DUAL;
        
        SELECT VALIDATE_CONVERSION('1999-12-01 11:00:00 -8:00'
            AS TIMESTAMP WITH TIME ZONE, 'YYYY-MM-DD HH:MI:SS TZH:TZM')
          FROM DUAL;
        
        SELECT VALIDATE_CONVERSION('11-May-16 17:30:00'
            AS TIMESTAMP WITH LOCAL TIME ZONE, 'DD-MON-YY HH24:MI:SS')
          FROM DUAL; 
        

        此外,从 12.2 开始,to_date 具有附加参数“默认...转换错误:https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/TO_DATE.html#GUID-D226FA7C-F7AD-41A0-BB1D-BD8EF9440118

        SELECT TO_DATE('Febuary 15, 2016, 11:00 A.M.'
               DEFAULT 'January 01, 2016 12:00 A.M.' ON CONVERSION ERROR,
               'Month dd, YYYY, HH:MI A.M.') "Value"
          FROM DUAL;
        
        Value
        ---------
        01-JAN-16
        

        因此您可以为此类情况指定特殊值,例如 Null。

        【讨论】:

          【解决方案4】:

          从 12.2 开始,语法为 to_date([expression] default null on conversion error, '[format]'):

          with dates (dates_col) as
               ( select '0201-05-31 00:00:00' from dual union all
                 select '31-May-2019 00:00:00' from dual union all
                 select 'TEXT' from dual union all
                 select '15-May-2019 00:00:00' from dual union all
                 select '01-Apr-2019 00:00:00' from dual union all
                 select '01-Apr-2019' from dual )
          select dates_col
               , to_date(dates_col default null on conversion error, 'DD-MON-YYYY HH24:MI:SS') as converted
          from   dates;
          
          DATES_COL            CONVERTED
          -------------------- -----------
          0201-05-31 00:00:00  
          31-May-2019 00:00:00 31/05/2019
          TEXT                 
          15-May-2019 00:00:00 15/05/2019
          01-Apr-2019 00:00:00 01/04/2019
          01-Apr-2019          01/04/2019
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-03-07
            • 1970-01-01
            • 2021-06-21
            • 1970-01-01
            • 2020-08-17
            相关资源
            最近更新 更多