sql >> Databasteknik >  >> RDS >> Oracle

Implementering av typ 2 SCD i Oracle

Här är ett tillvägagångssätt för att gruppera på varandra följande poster med samma nivå, samtidigt som ändringar upptäcks.

Tanken är att själv gå med i tabellen och relatera varje post till nästa post som har en annan nivå. Detta görs med en NOT EXISTS villkor med en korrelerad underfråga.

LEFT JOIN behövs för att undvika att filtrera bort den sista posten (som äger den aktuella nivån), som inte har en nästa post ännu :för denna post använder vi COALESCE() för att ställa in ett standardslutdatum.

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
    )

Detta returnerar :

 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

Nu kan vi gruppera posten efter nivå och slutdatum för att generera de förväntade resultaten. ROW_NUMBER() kan ge dig versionsnumret. Det är också enkelt att kontrollera vilken post som är den aktuella, som förklarats ovan.

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

Resultat:

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

I Oracle kan du förvandla valfri val till en sammanfogningsfråga med MERGE-syntaxen . Du kan matcha på alla förväntade kolumner current_flag och day_to och uppdatera dessa om en post redan finns; annars sätter du bara in en ny.

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. Allvarligt fel:Anrop till en medlemsfunktion bind_param() på boolean

  2. PostgreSQL:FEL:42601:en kolumndefinitionslista krävs för funktioner som returnerar post

  3. Oracle anser att tomma strängar är NULL medan SQL Server inte gör det - hur hanteras detta bäst?

  4. MySQL 5.7 &only_full_group_by