sql >> Databáze >  >> RDS >> Oracle

Oracle - převod mnoha formátů data na jedno formátované datum

Pokud máte dobrou představu o všech možných formátech data, mohlo by být jednodušší použít hrubou sílu:

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;
/

Uvědomte si, že moderní verze Oracle jsou s převodem data docela shovívavé. Tato funkce zpracovávala data ve formátech, které nejsou v seznamu, s některými zajímavými důsledky:

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> 

Což ukazuje limity automatického čištění dat tváří v tvář laxním pravidlům integrity dat. Mzda za hřích jsou poškozená data.

@AlexPoole upozorňuje na problém použití 'RR' formát. Tento prvek datové masky byl představen jako Y2K kludge. Je poněkud depresivní, že o tom stále diskutujeme téměř dvě desetiletí do nového tisíciletí.

Každopádně problém je v tomhle. Pokud přetypujeme tento řetězec '161225' do kdy má století? No, 'yymmdd'2016-12-15 . Slušné, ale co '991225' ? Jak pravděpodobné je, že datum, které opravdu chceme, je 2099-12-15 ? Zde je 'RR' do hry vstupuje formát. V zásadě má výchozí hodnotu století:čísla 00-49 výchozí hodnotu 20, výchozí hodnotu 50-99 hodnotu 19. Toto okno bylo určeno problémem Y2K:v roce 2000 bylo pravděpodobnější, že '98 odkazoval na nedávnou minulost než blízkou budoucnost a podobná logika platila pro '02 . Proto polovina cesty z roku 1950. Všimněte si, že toto je pevný bod ne posuvné okno. Jak se posouváme dále od roku 2000, tím méně užitečným se tento bod otáčení stává. Zjistěte více.

Klíčovým bodem každopádně je, že 'RRRR' si nehraje dobře s jinými formáty data:to_date('501212', 'rrrrmmdd') hurls ora-01843:není platný měsíc. So, use 'RR'and test for it before using 'YYYY''. Takže moje upravená funkce (s trochou úklidu) vypadá takto:

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;
/

Klíčovým bodem zůstává:existuje limit toho, jak chytře můžeme tuto funkci udělat, pokud jde o interpretaci dat, takže se ujistěte, že vedete nejlépe. Pokud si myslíte, že většina vašich datových řetězců odpovídá dni, měsíci a roku, uveďte to jako první; stále dostanete nějaké špatné sádry, ale méně, než když vedete s rokem-měsíc-den.



  1. Oracle SQL Developer 21.4.2 a SQLcl 21.4.1 jsou nyní k dispozici

  2. Uložte databázi mysql do zálohy ve formátu prostého textu (CSV) z příkazového řádku

  3. Přidání jednoho ze dvou nenulových omezení v postgresql

  4. Co znamená %Type v Oracle sql?