Oracle Date列清理

时间:2010-11-02 13:11:34

标签: oracle

我有一个table1(DueDate varchar2(20))。它有数千种不同格式的日期数据和一些不良数据,如字符。

例如。

YYYYMMDD,
MM/DD/YYYY,
MM-DD-YYYY,
M/D/YYYY,
'ABCD'
YYYYMMD,
YYYYMDD,

现在我必须得到逾期一周的日期。我该怎么做?

感谢您的帮助。

3 个答案:

答案 0 :(得分:6)

这是将日期信息存储在字符字段中的原因之一。

最简单的选择是创建一个函数,尝试使用您拥有的任何优先级顺序(即01020 2003年1月2日或2001年2月3日或其他内容)将字符串转换为日期并捕获异常。像

这样的东西
CREATE OR REPLACE FUNCTION my_to_date( p_str IN VARCHAR2 )
  RETURN DATE
IS
  l_date DATE;
BEGIN
  l_date := to_date( p_str, 'YYYYMMDD' );
  RETURN l_date;
EXCEPTION
  WHEN others THEN
    BEGIN
      l_date := to_date( p_str, 'MM/DD/YYYY' );
      RETURN l_date;
    EXCEPTION 
      WHEN others
      THEN
        RETURN null;
    END;
END;

有点像

SQL> CREATE OR REPLACE FUNCTION my_to_date( p_str IN VARCHAR2 )
  2    RETURN DATE
  3  IS
  4    l_date DATE;
  5  BEGIN
  6    l_date := to_date( p_str, 'YYYYMMDD' );
  7    RETURN l_date;
  8  EXCEPTION
  9    WHEN others THEN
 10      BEGIN
 11        l_date := to_date( p_str, 'MM/DD/YYYY' );
 12        RETURN l_date;
 13      EXCEPTION
 14        WHEN others
 15        THEN
 16          RETURN null;
 17      END;
 18  END;
 19  /

Function created.

SQL> select my_to_date( '19000101' ) from dual;

MY_TO_DAT
---------
01-JAN-00

SQL> ed
Wrote file afiedt.buf

  1* select my_to_date( '01/02/2005' ) from dual
SQL> /

MY_TO_DAT
---------
02-JAN-05

当然,您必须在代码中编写完整的有效日期格式代码,我只是处理列表中的前两个。

答案 1 :(得分:1)

这个答案建立在贾斯汀洞穴的基础之上。如果您创建另一个作为日期字段的列,则可以执行以下操作:

UPDATE table1 SET DueDate2 = my_to_date(DueDate) 
   WHERE DueDate2 IS NULL AND DueDate IS NOT NULL;

然后,您可以在每次修改函数中的日期格式后重新运行此更新。当未转换的所有日期都是无效日期(例如'ABCD')时,您必须停止。

答案 2 :(得分:0)

适用于Oracle 12.2的纯SQL解决方案,其中方便的default null on conversion error选项可避免编写函数和处理异常的需要:

with demo (date_string) as
     ( select '2018081' from dual union all
       select '01/8/2018' from dual union all
       select '01-8-2018' from dual union all
       select 'ABCD' from dual union all
       select '2018-08-01' from dual union all
       select '2018-01-8' from dual union all
       select '2017081' from dual union all
       select '01-AUG-2018' from dual
     )
select t.date_string
     , coalesce
       ( to_date(t.date_string default null on conversion error)
       , case sys_context('USERENV','NLS_TERRITORY')
              when 'AMERICA' then to_date(t.date_string default null on conversion error,'MM/DD/YYYY')
              else to_date(t.date_string default null on conversion error,'DD/MM/YYYY')
         end
       , to_date(t.date_string default null on conversion error,'DD/MM/YYYY')
       , to_date(t.date_string default null on conversion error,'YYYY/MM/DD')
       , to_date(t.date_string default null on conversion error,'YYYYMMDD')
       , to_date(t.date_string default null on conversion error,'DD/MON/YYYY')
       ) as converted_date
from   demo t

结果:

DATE_STRING CONVERTED_DATE
----------- --------------
2018081     01-AUG-2018
01/8/2018   08-JAN-2018
01-8-2018   08-JAN-2018
ABCD
2018-08-01  01-AUG-2018
2018-01-8   08-JAN-2018
2017081     01-AUG-2017
01-AUG-2018 01-AUG-2018

第一个测试未指定任何格式以使用会话默认值(DD-MON-RRRR等)。

接下来的测试试图处理北美将月份放在首位的习惯。 (我不确定sys_context('USERENV','NLS_TERRITORY') = 'AMERICA'是否是一个可靠的测试,因为它往往是默认设置,无论实际区域如何。但它说明了如何在需要时注入一些条件逻辑。)

to_date对分隔符字符非常宽容,因此我没有为DD-MON-YYYYDD/MON/YYYY等指定不同的格式。