跟踪T-SQL中每个表列的数据更改

时间:2016-01-19 10:51:01

标签: sql sql-server tsql

根据下表,我想获取price的每个值的两列qtyfruit的更改历史记录。我使用的是MS SQL Server 2012。

例如:

  • 第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  |
+----+----+--------+--------+--------+---------+

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

以下答案的前提条件是priceqty具有相同的数据类型,而idIDENTITY列。

第一步是找到变化。您可以通过数字化由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;

由于您无法删除多个列,因此最终SELECT中的案例是不可避免的。