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'
dá 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.