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

Oracleでのタイプ2SCDの実装

    これは、変更を検出しながら、同じ層を持つ連続したレコードをグループ化する方法です。

    アイデアは、テーブルを自己結合し、各レコードを異なる層を持つ次のレコードに関連付けることです。これは、NOT EXISTSを使用して行われます 相関サブクエリを使用した条件。

    LEFT JOIN 次のレコードがまだない最後のレコード(現在の層を所有している)が除外されないようにするために必要です。このレコードには、COALESCE()を使用します。 デフォルトの終了日を設定します。

    SELECT 
        c1.day day_from,
        COALESCE(c2.day, TO_DATE('2199-12-31', 'yyyy-mm-dd')) day_to,
        c1.Vendor_ID,
        c1.Customer_ID, 
        c1.rank
    FROM customer_records c1
    LEFT JOIN customer_records c2 
        ON  c2.Vendor_ID = c1.Vendor_ID
        AND c2.Customer_ID         = c1.Customer_ID
        AND c2.rank <> c1.rank
        AND c2.DAY                 > c1.DAY
        AND NOT EXISTS (
            SELECT 1
            FROM customer_records c3
            WHERE
                    c3.Vendor_ID = c1.Vendor_ID
                AND c3.Customer_ID         = c1.Customer_ID
                AND c3.rank <> c1.rank
                AND c3.DAY                 > c1.DAY
                AND c3.DAY                 < c2.DAY
        )
    

    これは:

    を返します
     DAY_FROM  | DAY_TO    | Vendor_ID | Customer_ID | rank
     :-------- | :-------- | ------------------: | ----------: | -----------------:
     24-SEP-14 | 22-OCT-14 |            71047795 |      476095 |               3103
     01-OCT-14 | 22-OCT-14 |            71047795 |      476095 |               3103
     08-OCT-14 | 22-OCT-14 |            71047795 |      476095 |               3103
     15-OCT-14 | 22-OCT-14 |            71047795 |      476095 |               3103
     22-OCT-14 | 12-NOV-15 |            71047795 |      476095 |               3102
     29-OCT-14 | 12-NOV-15 |            71047795 |      476095 |               3102
     05-NOV-15 | 12-NOV-15 |            71047795 |      476095 |               3102
     12-NOV-15 | 31-DEC-99 |            71047795 |      476095 |               3103
    

    これで、レコードセットを階層と終了日でグループ化して、期待される結果を生成できます。 ROW_NUMBER() バージョン番号を教えてくれます。上で説明したように、どのレコードが現在のレコードであるかを確認することも簡単です。

    SELECT 
        ROW_NUMBER() OVER(ORDER BY c2.day) version,
        DECODE(c2.day, NULL, 'Y') current_flag,
        MIN(c1.day) day_from,
        COALESCE(c2.day, TO_DATE('2199-12-31', 'yyyy-mm-dd')) day_to,
        c1.Vendor_ID,
        c1.Customer_ID, 
        c1.rank
    FROM customer_records c1
    LEFT JOIN customer_records c2 
        ON  c2.Vendor_ID = c1.Vendor_ID
        AND c2.Customer_ID         = c1.Customer_ID
        AND c2.rank <> c1.rank
        AND c2.DAY                 > c1.DAY
        AND NOT EXISTS (
            SELECT 1
            FROM customer_records c3
            WHERE
                    c3.Vendor_Id = c1.Vendor_Id
                AND c3.Customer_ID         = c1.Customer_ID
                AND c3.rank <> c1.rank
                AND c3.DAY                 > c1.DAY
                AND c3.DAY                 < c2.DAY
        )
    GROUP BY
        c1.Vendor_Id, 
        c1.Customer_ID, 
        c1.rank, 
        c2.day
    ORDER BY
        day_from
    

    結果:

    VERSION | CURRENT_FLAG | DAY_FROM  | DAY_TO    | Vendor_ID | Customer_ID | rank
    ------: | :----------- | :-------- | :-------- | ------------------: | ----------: | -----------------:
          1 | N            | 24-SEP-14 | 22-OCT-14 |            71047795 |      476095 |               3103
          2 | N            | 22-OCT-14 | 12-NOV-15 |            71047795 |      476095 |               3102
          3 | Y            | 12-NOV-15 | 31-DEC-99 |            71047795 |      476095 |               3103
    

    Oracleでは、MERGE構文current_flagが予想されるすべての列で一致させることができます およびday_to 、およびレコードがすでに存在する場合はこれらを更新します;それ以外の場合は、新しいものを挿入するだけです。

    MERGE INTO dimensions dim
    USING (
       -- above query goes here --
    ) cust 
        ON  dim.DAY_FROM            = cust.DAY_FROM
        AND dim.vendor_id = cust.vendor_id
        AND dim.Customer_ID         = cust.Customer_ID
        AND dim.rank  = cust.rank
    WHEN MATCHED THEN UPDATE SET 
        dim.DAY_TO = cust.DAY_TO,
        dim.CURRENT_FLAG = cust.CURRENT_FLAG
    WHEN NOT MATCHED THEN 
        INSERT (
            dim.DAY_FROM, 
            dim.VERSION, 
            dim.CURRENT_FLAG, 
            dim.DAY_FROM, 
            dim.DAY_TO, 
            dim.vendor_id, 
            dim.customer_id, 
            dim.rank
        ) VALUES (
            cust.DAY_FROM, 
            cust.VERSION, 
            cust.CURRENT_FLAG, 
            cust.DAY_FROM, 
            cust.DAY_TO, 
            cust.vendor_id, 
            cust.Customer_ID, 
            cust.rank
        )
    


    1. MySQL:フィールドを0に設定してすべての行を更新しますが、1つの行のフィールドを1に設定します

    2. SQLServerで日付と時刻を操作する際の問題のトラブルシューティング

    3. SQL ServerIntegrationServicesを使用したOracleデータベースへの接続

    4. さまざまな条件でのOracleの注文