2016-01-19 4 views
1

Учитывая приведенную ниже таблицу, я хочу получить историю изменений для двух столбцов price и qty для каждого значения fruit. Я использую MS SQL Server 2012.Отслеживание изменений данных для каждого столбца таблицы в T-SQL

Так, например:

  • изменение между рядами 1 и 3 в том, что цены на яблоки пошли от 10 до 30, что дает строку 1 в таблице результатов ниже.
  • изменение между строками 2 и 4 состояло в том, что цена бананов составляла от 20 до 30 , а количество было от 2 до 3, что дает строки 2 и 3 в таблице результатов .

Есть ли способ сделать это? Есть ли способ сделать это эффективно?

Источник таблица таблица

+----+---------+--------+--------+---------+ 
| id | fruit | price | qty | created | 
+----+---------+--------+--------+---------+ 
| 1 | apples | 10  | 1  | 1/1/16 | 
+----+---------+--------+--------+---------+ 
| 2 | bananas | 20  | 2  | 1/1/16 | 
+----+---------+--------+--------+---------+ 
| 3 | apples | 30  | 1  | 2/1/16 | 
+----+---------+--------+--------+---------+ 
| 4 | bananas | 30  | 3  | 2/1/16 | 
+----+---------+--------+--------+---------+ 
| 5 | apples | 30  | 2  | 3/1/16 | 
+----+---------+--------+--------+---------+ 
| 6 | apples | 30  | 3  | 7/1/16 | 
+----+---------+--------+--------+---------+ 

Результаты

+----+----+--------+--------+--------+---------+ 
| id | fk | col | oldval | newval | changed | 
+----+----+--------+--------+--------+---------+ 
| 1 | 3 | price | 10  | 30  | 2/1/16 | 
+----+----+--------+--------+--------+---------+ 
| 2 | 4 | price | 20  | 30  | 2/1/16 | 
+----+----+--------+--------+--------+---------+ 
| 3 | 4 | qty | 2  | 3  | 2/1/16 | 
+----+----+--------+--------+--------+---------+ 
| 4 | 5 | qty | 1  | 2  | 3/1/16 | 
+----+----+--------+--------+--------+---------+ 
| 5 | 6 | qty | 2  | 3  | 7/1/16 | 
+----+----+--------+--------+--------+---------+ 

ответ

4

Вот один из способов:

;WITH LagCTE AS (
    SELECT id, fruit, price, qty, created, 
      LAG(price) OVER (PARTITION BY fruit 
          ORDER BY created) AS prevPrice, 
      LAG(qty) OVER (PARTITION BY fruit 
         ORDER BY created) AS prevQty 
    FROM mytable 
) 
SELECT ROW_NUMBER() OVER (ORDER BY changed) AS id, 
     fk, col, oldval, newval, changed 
FROM (  
    SELECT id AS fk, fruit, 'price' AS col, 
     prevPrice AS oldval, price AS newval, 
     created AS changed 
    FROM LagCTE 
    WHERE prevPrice <> price 

    UNION ALL 

    SELECT id AS fk, fruit, 'qty' AS col, 
     prevQty AS oldval, qty AS newval, 
     created AS changed 
    FROM LagCTE 
    WHERE prevQty <> qty) AS t 

Demo here

+0

Как это работает? – rickythefox

+0

@ rickythefox Вы можете попробовать оба решения до сих пор и рассказать нам, как они работают с вашими фактическими данными. –

1

Предпосылками для следующего ответа является то, что price и qty имеют одинаковый тип данных, а id - столбец IDENTITY.

Первый шаг - найти изменения. Вы можете сделать это, указав все записи одного и того же фрукта, заказанные по нему id, а затем присоединитесь к последующим записям. Тогда вы можете получить UNPIVOT результат и отфильтровать неизменные колоды.

WITH 
    SourceNumbered AS 
     (
     SELECT 
       ROW_NUMBER() OVER(PARTITION BY fruit ORDER BY id) AS nr, 
       id, fruit, price, qty, created 
      FROM 
       SourceTable 
    ), 
    SourceUnpivoted AS 
     (
     SELECT 
       U.id, U.fk, U.col 
      FROM 
       (
        SELECT 
         L.id, R.id AS fk, 
         L.price - R.price AS price, 
         L.qty - R.qty AS qty 
        FROM 
         SourceNumbered L 
         INNER JOIN SourceNumbered R 
          ON R.fruit = L.fruit 
           AND R.nr = L.nr + 1 
       ) D 
      UNPIVOT (value FOR col IN (price, qty)) U 
      WHERE 
       value != 0 
    ) 
SELECT 
     U.id, U.fk, U.col, 
     CASE U.col 
     WHEN 'price' 
      THEN O.price 
     WHEN 'qty' 
      THEN O.qty 
     END AS oldval, 
     CASE U.col 
     WHEN 'price' 
      THEN N.price 
     WHEN 'qty' 
      THEN N.qty 
     END AS oldval, 
     N.created AS changed 
    FROM 
     SourceUnpivoted U 
     INNER JOIN SourceTable O 
     ON O.id = U.id 
     INNER JOIN SourceTable N 
     ON N.id = U.fk; 

Поскольку вы не можете UNPIVOT более одного столбца, случай, в конечном SELECT является неизбежным.

+0

Спасибо за ваш ответ! – rickythefox

Смежные вопросы