Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Orakel - Konvertieren Sie viele Datumsformate in ein einziges formatiertes Datum

Wenn Sie eine gute Vorstellung von allen möglichen Datumsformaten haben, ist es möglicherweise einfacher, Brute Force zu verwenden:

create or replace function clean_date
    ( p_date_str in varchar2)
    return date
is
    l_dt_fmt_nt sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll
        ('DD-MON-YYYY', 'DD-MON-YY', 'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD'
         , 'DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY/MM/DD', 'DD/MM/YY', 'MM/DD/YY');
    return_value date;
begin
    for idx in l_dt_fmt_nt.first()..l_dt_fmt_nt.last()
    loop
        begin
            return_value := to_date(p_date_str, l_dt_fmt_nt(idx));
            exit;
        exception
             when others then null;
        end;
    end loop;
    if return_value is null then
        raise no_data_found; 
    end if;
    return return_value;
exception
    when no_data_found then
        raise_application_error(-20000, p_date_str|| ' is unknown date format');
end clean_date;
/

Beachten Sie, dass moderne Versionen von Oracle die Datumskonvertierung recht verzeihen. Diese Funktion handhabte Datumsangaben in Formaten, die nicht in der Liste enthalten sind, mit einigen interessanten Konsequenzen:

SQL> select  clean_date('20160817') from dual;

CLEAN_DAT
---------
17-AUG-16

SQL> select  clean_date('160817') from dual;

CLEAN_DAT
---------
16-AUG-17

SQL> 

Was die Grenzen der automatisierten Datenbereinigung angesichts laxer Datenintegritätsregeln aufzeigt. Der Lohn der Sünde sind verfälschte Daten.

@AlexPoole spricht die Frage der Verwendung von 'RR' an Format. Dieses Element der Datumsmaske wurde als Y2K-Kludge eingeführt. Es ist ziemlich deprimierend, dass wir fast zwei Jahrzehnte nach Beginn des neuen Jahrtausends immer noch darüber diskutieren.

Wie auch immer, das Problem ist folgendes. Wenn wir diesen String umwandeln '161225' zu einem Datum welches Jahrhundert hat es? Nun, 'yymmdd' gibt 2016-12-15 . Fair genug, aber was ist mit '991225' ? Wie wahrscheinlich ist es, dass das gewünschte Datum 2099-12-15 ist ? Hier steht der 'RR' Format kommt ins Spiel. Grundsätzlich ist das Jahrhundert voreingestellt:Zahlen 00-49 voreingestellt auf 20, 50-99 voreingestellt auf 19. Dieses Fenster wurde durch das Jahr-2000-Problem bestimmt:im Jahr 2000 war es wahrscheinlicher, dass '98 bezog sich eher auf die jüngste Vergangenheit als auf die nahe Zukunft, und eine ähnliche Logik galt für '02 . Daher die Halbzeit von 1950. Beachten Sie, dass dies ein Fixpunkt ist kein Schiebefenster. Je weiter wir uns vom Jahr 2000 entfernen, desto weniger nützlich wird dieser Drehpunkt. Erfahren Sie mehr.

Wie auch immer, der entscheidende Punkt ist, dass 'RRRR' nicht gut mit anderen Datumsformaten zusammenspielt:to_date('501212', 'rrrrmmdd') hurls ora-01843:kein gültiger Monat . So, use 'RR'and test for it before using 'JJJJ'`. Meine überarbeitete Funktion (mit etwas Aufräumen) sieht also so aus:

create or replace function clean_date
    ( p_date_str in varchar2)
    return date
is
    l_dt_fmt_nt sys.dbms_debug_vc2coll := sys.dbms_debug_vc2coll
        ('DD-MM-RR', 'MM-DD-RR', 'RR-MM-DD', 'RR-DD-MM'
         , 'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD', 'YYYY-DD-MM');
    return_value date;
begin
    for idx in l_dt_fmt_nt.first()..l_dt_fmt_nt.last()
    loop
        begin
            return_value := to_date(p_date_str, l_dt_fmt_nt(idx));
            exit;
        exception
             when others then null;
        end;
    end loop;
    if return_value is null then
        raise no_data_found; 
    end if;
    return return_value;
exception
    when no_data_found then
        raise_application_error(-20000, p_date_str|| ' is unknown date format');
end clean_date;
/

Der entscheidende Punkt bleibt:Es gibt eine Grenze dafür, wie intelligent wir diese Funktion machen können, wenn es darum geht, Datumsangaben zu interpretieren, also stellen Sie sicher, dass Sie mit der besten Anpassung beginnen. Wenn Sie denken, dass die meisten Ihrer Datumszeichenfolgen Tag-Monat-Jahr passen, setzen Sie das zuerst; Sie werden immer noch einige falsche Abgüsse bekommen, aber weniger, wenn Sie mit Jahr-Monat-Tag führen.