[英]Tracking data changes per table column in T-SQL
Given the table below I want to get the history of changes for the two columns price
and qty
for each value of fruit
. 给定下表,我想获取两列
price
和每个fruit
值的qty
变化的历史记录。 I'm using MS SQL Server 2012. 我正在使用MS SQL Server 2012。
So for example: 因此,例如:
Is there a way to do this? 有没有办法做到这一点? Is there also a way to do this efficiently?
有没有办法有效地做到这一点?
Source table 源表
+----+---------+--------+--------+---------+
| 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 |
+----+---------+--------+--------+---------+
Results table 结果表
+----+----+--------+--------+--------+---------+
| 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 |
+----+----+--------+--------+--------+---------+
Here's one way: 这是一种方法:
;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
Preconditions for the following answer are that price
and qty
have the same datatype and id
is an IDENTITY
column. 以下答案的前提条件是
price
和qty
具有相同的数据类型,并且id
是IDENTITY
列。
The first step is to find changes. 第一步是找到更改。 You can do that by numering all records of the same fruit ordered by it's
id
and then join subsequent records. 您可以通过对
id
排序的同一水果的所有记录进行id
,然后加入后续记录来做到这一点。 Then you can UNPIVOT
the result and filter unchanged colums out. 然后,你可以
UNPIVOT
结果,并进行过滤不变colums。
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;
Since you can't unpivot more than one column, the case in the final SELECT
is unavoidable. 由于您不能取消旋转多于一列,因此最终
SELECT
情况不可避免。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.