【问题标题】:How can we extract date only from a column with various date and string formats in Oracle?我们如何仅从 Oracle 中具有各种日期和字符串格式的列中提取日期?
【发布时间】:2021-12-09 07:28:08
【问题描述】:
ACTUAL expected
SEP-10-2017 10-SEP-2017
SEP 30 2018 30-SEP-2018
OFFICE OF SMALL
OCT-11-2018 11-OCT-2018
O9-SEP-2009 O9-SEP-2009
Not Applicable
NOV-20-2001 20-NOV-2001
BANIJYA BHIBAG
AUGUST 03 2017 03-AUG-2017
AUG-04-1991 04-AUG-1991
97/2015
09/09/2018 09-SEP-2018

我们如何才能得到如上的结果并丢弃无法转换的日期?

【问题讨论】:

标签: oracle plsql


【解决方案1】:

从 Oracle 12 开始,您不需要 PL/SQL 并且可以使用:

SELECT actual,
       COALESCE(
         TO_DATE(
           actual DEFAULT NULL ON CONVERSION ERROR,
           'MM-DD-YYYY',
           'NLS_DATE_LANGUAGE=ENGLISH'
         ),
         TO_DATE(
           actual DEFAULT NULL ON CONVERSION ERROR,
           'DD-MON-YYYY',
           'NLS_DATE_LANGUAGE=ENGLISH'
         )
       ) AS parsed
FROM   table_name;

其中,对于样本数据:

CREATE TABLE table_name (ACTUAL) AS
SELECT 'SEP-10-2017'     FROM DUAL UNION ALL
SELECT 'SEP 30 2018'     FROM DUAL UNION ALL
SELECT 'OFFICE OF SMALL' FROM DUAL UNION ALL
SELECT 'OCT-11-2018'     FROM DUAL UNION ALL
SELECT 'O9-SEP-2009'     FROM DUAL UNION ALL
SELECT 'Not Applicable'  FROM DUAL UNION ALL
SELECT 'NOV-20-2001'     FROM DUAL UNION ALL
SELECT 'BANIJYA BHIBAG'  FROM DUAL UNION ALL
SELECT 'AUGUST 03 2017'  FROM DUAL UNION ALL
SELECT 'AUG-04-1991'     FROM DUAL UNION ALL
SELECT '97/2015'         FROM DUAL UNION ALL
SELECT '09/09/2018'      FROM DUAL;

输出:

ACTUAL PARSED
SEP-10-2017 10-SEP-2017
SEP 30 2018 30-SEP-2018
OFFICE OF SMALL
OCT-11-2018 11-OCT-2018
O9-SEP-2009
Not Applicable
NOV-20-2001 20-NOV-2001
BANIJYA BHIBAG
AUGUST 03 2017 03-AUG-2017
AUG-04-1991 04-AUG-1991
97/2015
09/09/2018 09-SEP-2018

注意:O9-SEP-2009 尚未解析,因为您将字母 O 而不是数字 0 作为第一个字符。

db小提琴here

【讨论】:

  • @MTO 做得很好
  • @MT0 ,按预期工作。
【解决方案2】:

一种选择是创建一个涵盖所有可能组合的函数。以下示例包含其中一些 - 您必须在找到它们时添加新的。

SQL> create or replace function f_date (par_str in varchar2)
  2    return date
  3  is
  4    l_date date;
  5  begin
  6    begin
  7      l_date := to_date(par_str, 'mon-dd-yyyy');
  8      return l_date;
  9    exception
 10      when others then null;
 11    end;
 12
 13    --
 14
 15    begin
 16      l_date := to_date(par_str, 'mon dd yyyy');
 17      return l_date;
 18    exception
 19      when others then null;
 20    end;
 21
 22    --
 23
 24    begin
 25      l_date := to_date(par_str, 'dd-mon-yyyy');
 26      return l_date;
 27    exception
 28      when others then null;
 29    end;
 30
 31    --
 32
 33    begin
 34      l_date := to_date(par_str, 'month dd yyyy');
 35      return l_date;
 36    exception
 37      when others then null;
 38    end;
 39
 40    --
 41
 42    begin
 43      l_date := to_date(par_str, 'dd/mm/yyyy');
 44      return l_date;
 45    exception
 46      when others then null;
 47    end;
 48
 49    return null;
 50
 51  exception
 52    when others then
 53      return null;
 54  end f_date;
 55  /

Function created.

测试:

SQL> select actual, f_date(actual) as expected
  2  from test;

ACTUAL          EXPECTED
--------------- -----------
SEP-10-2017     10-SEP-2017
SEP 30 2018     30-SEP-2018
OFFICE OF SMALL
09-SEP-2009     09-SEP-2009
Not applicable
AUGUST 03 2017  03-AUG-2017
97/2015
09/09/2018      09-SEP-2018

8 rows selected.

SQL>

可能的问题:如果actual = 09/10/12,是什么?

  • 09 可以是日、月或年
  • 10 也可以是日、月或年
  • 12 也可以是日、月或年

那么,它是什么?

  • 2012 年 10 月 9 日
  • 2012 年 9 月 10 日
  • 2009 年 10 月 12 日
  • ...

【讨论】:

    【解决方案3】:

    如果您确定对于可以转换为日期值的值没有任何其他类型的格式(例如,所有数据都符合此示例数据集),请使用下面的代码块是为了在另一个表(t2)中填充合适的日期值,同时显示腐烂的值,例如

    SQL> SET SERVEROUTPUT ON
    SQL> DECLARE
      dt DATE;
    BEGIN
      FOR c IN (SELECT * FROM t) LOOP
        BEGIN
          dt := TO_DATE(c.col, 'MON-DD-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH');
          INSERT INTO t2 VALUES(c.id,c.col);
        EXCEPTION
          WHEN OTHERS THEN
            BEGIN
              dt := TO_DATE(c.col, 'DD/MM/YYYY', 'NLS_DATE_LANGUAGE=ENGLISH');
              INSERT INTO t2 VALUES(c.id,c.col);
            EXCEPTION
              WHEN OTHERS THEN
                DBMS_OUTPUT.PUT_LINE(c.col || ' is not a valid date value');          
            END;
        END;
      END LOOP;
      COMMIT;
    END;
    /
    

    Demo

    【讨论】:

      猜你喜欢
      • 2015-06-18
      • 1970-01-01
      • 1970-01-01
      • 2020-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多