我们如何仅从 Oracle 中具有各种日期和字符串格式的列中提取日期?

Posted

技术标签:

【中文标题】我们如何仅从 Oracle 中具有各种日期和字符串格式的列中提取日期?【英文标题】:How can we extract date only from a column with various date and string formats in 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

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

【问题讨论】:

嗨,尼泊尔,请在“问汤姆”asktom.oracle.com/pls/apex/… 上查看这个答案 【参考方案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

【讨论】:

以上是关于我们如何仅从 Oracle 中具有各种日期和字符串格式的列中提取日期?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅从日期时间列中获取日期? [复制]

SQL Server 2008 仅从字段中选择日期 [重复]

如何仅从组中查询具有最新时间戳的文档?

如何仅从 sql server 2008 中的日期中提取年份?

oracle数据库如何改变日期格式

如何获取数据列表,特定日期仅从每个日期获取 6 条记录而不是更多