sql >> Database teknologi >  >> RDS >> Sqlserver

Hvordan kan jeg skrive en forespørgsel for at udtrække individuelle ændringer fra snapshots af data?

Her er et arbejdseksempel, der bruger UNPIVOT. Det er baseret på mit svar på mit spørgsmål Bedre måde at delvis UNPIVOT i par i SQL

Dette har nogle gode funktioner.

  1. Det er nemt at tilføje yderligere felter. Du skal blot tilføje værdier til SELECT- og UNPIVOT-sætningen. Du behøver ikke tilføje yderligere UNION-sætninger

  2. Where-sætningen WHERE curr.value <> prev.value ændres aldrig, uanset hvor mange felter der tilføjes.

  3. Ydeevnen er overraskende hurtig.

  4. Den er bærbar til nuværende versioner af Oracle, hvis du har brug for det

SQL

Declare @Snapshots as table(
Sequence int,
DateTaken      datetime,
[id] int,
field1 varchar(20),
field2 int)



INSERT INTO @Snapshots VALUES 

      (1,    '2011-01-01',      1,     'Red',          2),
      (2,    '2011-01-01',      2,     'Blue',        10),
      (3,    '2011-02-01',      1,     'Green',        2),
      (4,    '2011-03-01',      1,     'Green' ,       3),
      (5,    '2011-03-01',      2,     'Purple',       2),
      (6,    '2011-04-01',      1,     'Yellow',       2)

;WITH Snapshots (Sequence, DateTaken, ID, Field1, Field2, _Index)
AS
(
    SELECT Sequence, DateTaken, ID, Field1, Field2, ROW_NUMBER() OVER (ORDER BY ID, Sequence) _Index
    FROM @Snapshots
)
,  data as(
SELECT
     c._Index
    , c.DateTaken
    ,  c.ID
    , cast(c.Field1  as varchar(max)) Field1
    , cast(p.Field1  as varchar(max))Field1_Previous
    , cast(c.Field2   as varchar(max))Field2
    , cast(p.Field2  as varchar(max)) Field2_Previous 


FROM Snapshots c
JOIN Snapshots p ON p.ID = c.ID AND (p._Index + 1) = c._Index
)


, fieldsToRows 
     AS (SELECT DateTaken, 
                id,
                _Index,
                value,
                field

         FROM   data p UNPIVOT (value FOR field IN (field1, field1_previous, 
                                                        field2, field2_previous) ) 
                AS unpvt
        ) 
SELECT 
    curr.DateTaken,
    curr.ID,
    curr.field,
    prev.value previous,
    curr.value 'current'

FROM 
        fieldsToRows curr 
        INNER  JOIN  fieldsToRows prev
        ON curr.ID = prev.id
            AND curr._Index = prev._Index 
            AND curr.field + '_Previous' = prev.field
WHERE 
    curr.value <> prev.value

Output

DateTaken               ID          field     previous current
----------------------- ----------- --------- -------- -------
2011-02-01 00:00:00.000 1           Field1    Red      Green
2011-03-01 00:00:00.000 1           Field2    2        3
2011-04-01 00:00:00.000 1           Field1    Green    Yellow
2011-04-01 00:00:00.000 1           Field2    3        2
2011-03-01 00:00:00.000 2           Field1    Blue     Purple
2011-03-01 00:00:00.000 2           Field2    10       2


  1. Entity Framework/SQL2008 - Hvordan opdateres LastModified-felter automatisk for enheder?

  2. Trin til at installere MySQL8 på CentOS

  3. Hvordan får man den næste værdi i en sekvens ind i en variabel?

  4. Opdel en MYSQL-streng fra GROUP_CONCAT i en (array, like, udtryk, liste), som IN () kan forstå