Oracle
 sql >> Baza danych >  >> RDS >> Oracle

oracle - konwertuj wiele formatów daty na jedną sformatowaną datę

Jeśli masz dobry pomysł na wszystkie możliwe formaty dat, może być łatwiej użyć brutalnej siły:

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

Należy pamiętać, że współczesne wersje Oracle są dość wyrozumiałe w przypadku konwersji dat. Ta funkcja obsługiwała daty w formatach, których nie ma na liście, z kilkoma interesującymi konsekwencjami:

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 pokazuje ograniczenia automatycznego czyszczenia danych w obliczu luźnych zasad integralności danych. Zapłatą za grzech są uszkodzone dane.

@AlexPoole podnosi kwestię używania 'RR' format. Ten element maski daty został wprowadzony jako paczka Y2K. To raczej przygnębiające, że wciąż dyskutujemy o tym prawie dwie dekady nowego tysiąclecia.

W każdym razie problem polega na tym. Jeśli rzucimy ten ciąg '161225' do tej pory jaki ma wiek? Cóż, 'yymmdd' da 2016-12-15 . W porządku, ale co z '991225' ? Jakie jest prawdopodobieństwo, że data, której naprawdę chcemy, to 2099-12-15 ? W tym miejscu 'RR' w grę wchodzi format. Zasadniczo domyślnie ustawia wiek:liczby 00-49 domyślnie na 20, 50-99 domyślnie na 19. To okno zostało określone przez kwestię Y2K:w 2000 r. było bardziej prawdopodobne, że '98 odnosiło się do niedalekiej przeszłości niż niedalekiej przyszłości i podobna logika zastosowana do '02 . Stąd połowa roku 1950. Pamiętaj, że jest to punkt stały nie przesuwne okno. Im dalej od roku 2000, tym mniej użyteczny staje się ten punkt obrotu. Dowiedz się więcej.

W każdym razie kluczową kwestią jest to, że 'RRRR' nie działa dobrze z innymi formatami dat:to_date('501212', 'rrrrmmdd') hurls ora-01843:niepoprawny miesiąc. So, use 'RR'and test for it before using „RRRR”. Więc moja poprawiona funkcja (z pewnym porządkiem) wygląda tak:

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

Kluczową kwestią pozostaje:istnieje granica tego, jak sprytnie możemy stworzyć tę funkcję, jeśli chodzi o interpretację dat, więc upewnij się, że prowadzisz z najlepszym dopasowaniem. Jeśli uważasz, że większość twoich ciągów dat pasuje do dnia-miesiąca-roku, umieść to jako pierwsze; nadal będziesz mieć złe rzuty, ale mniej, jeśli prowadzisz rok-miesiąc-dzień.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. jak łączyć ciągi?

  2. Jaki jest odpowiednik tabeli Oracle Dual w MS SqlServer?

  3. Jak wykorzystać istniejącą sekwencję Oracle do wygenerowania identyfikatora w stanie hibernacji?

  4. CURRENT_DATE Funkcja w Oracle

  5. Obsługa błędów Oracle