sql >> データベース >  >> RDS >> Oracle

oracle-多くの日付形式を単一の形式の日付に変換します

    考えられるすべての日付形式について適切な考えがある場合は、ブルートフォースを使用する方が簡単な場合があります:

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

    最新バージョンのOracleは、日付変換に非常に寛容であることに注意してください。この関数は、リストにない形式で日付を処理し、いくつかの興味深い結果をもたらしました:

    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> 
    

    これは、緩いデータ整合性ルールに直面した場合の自動データクレンジングの限界を示しています。罪の賃金は堕落したデータです。

    @AlexPooleは、'RR'を使用する問題を提起します フォーマット。日付マスクのこの要素は、Y2K問題として導入されました。新しいミレニアムのほぼ20年後も、まだ話し合っているのはかなり気のめいることです。

    とにかく、問題はこれです。この文字列をキャストすると'161225' 日付までにそれは何世紀になりますか?さて、'yymmdd' 2016-12-15を提供します 。十分に公平ですが、'991225'はどうでしょうか。 ?私たちが本当に望んでいる日付が2099-12-15である可能性はどのくらいありますか ?ここが'RR' フォーマットが登場します。基本的に、世紀のデフォルトです。00〜49の数字は20にデフォルト設定され、50〜99のデフォルトは19になります。このウィンドウは、2000年問題によって決定されました。2000年には、'98の可能性が高くなりました。 近い将来よりも最近の過去を参照し、同様のロジックを'02に適用しました 。したがって、1950年の中間点です。これは固定点であることに注意してください。 スライディングウィンドウではありません。 2000年からさらに進むと、ピボットポイントの有用性が低下します。詳細をご覧ください。

    とにかく、重要な点は、「RRRR」が他の日付形式とうまく機能しないことです:to_date('501212', 'rrrrmmdd') hurls ora-01843:有効な月. So, useを使用します 'RR'and test for it before using 'YYYY'`。したがって、私の改訂された関数(多少の整理を含む)は次のようになります:

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

    重要な点は残っています。日付の解釈に関しては、この機能をどれだけ賢くすることができるかには限界があるので、最適な方法でリードするようにしてください。ほとんどの日付文字列が日-月-年に適合すると思う場合は、それを最初に置きます。あなたはまだいくつかの間違ったキャストを得るでしょう、しかしあなたが年-月-日でリードするならばそれより少ないです。



    1. ソフトウェアレビュー–MSSQLのステラ修復

    2. SQL Serverのセッションコンテキストでのキーと値のペアの設定(sp_set_session_context)

    3. PL / SQLにはJavaと同等のStringTokenizerがありますか?

    4. Ubuntu20.04にZabbixをインストールして設定する方法