sql >> Databáze >  >> RDS >> Sqlserver

Jak mohu napsat dotaz pro extrahování jednotlivých změn ze snímků dat?

Zde je pracovní ukázka, která používá UNPIVOT. Je to založeno na mé odpovědi na mou otázku Lepší způsob, jak částečně UNPIVOT v Pairs v SQL

To má několik pěkných funkcí.

  1. Přidání dalších polí je snadné. Stačí přidat hodnoty do klauzule SELECT a UNPIVOT. Nemusíte přidávat další klauzule UNION

  2. Klauzule where WHERE curr.value <> prev.value se nikdy nemění bez ohledu na to, kolik polí je přidáno.

  3. Výkon je překvapivě rychlý.

  4. Pokud to potřebujete, je přenosný na aktuální verze Oracle

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

Výstup

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. Proč se dotaz drasticky zpomalí, pokud je v klauzuli WHERE konstanta nahrazena parametrem (se stejnou hodnotou)?

  2. Volání API z uložené procedury SQL Server

  3. Vysvětlení SQL Server (localdb)\v11.0

  4. oracle pl/sql výsledky do jednoho řetězce