跟踪T-SQL中每个表列的数据更改
根据下表,我想得到两列每种水果的价格和数量的变化历史。我正在使用MS SQL Server 2012 例如: 第1行和第3行之间的变化是苹果的价格从 10至30,给出下表结果中的第1行。 变化 第二排和第四排之间是香蕉的价格从20涨到了30 数量从2到3,这就给出了表中的第2行和第3行 结果表。 有办法做到这一点吗?有没有一种方法可以有效地做到这一点 源表跟踪T-SQL中每个表列的数据更改,sql,sql-server,tsql,Sql,Sql Server,Tsql,根据下表,我想得到两列每种水果的价格和数量的变化历史。我正在使用MS SQL Server 2012 例如: 第1行和第3行之间的变化是苹果的价格从 10至30,给出下表结果中的第1行。 变化 第二排和第四排之间是香蕉的价格从20涨到了30 数量从2到3,这就给出了表中的第2行和第3行 结果表。 有办法做到这一点吗?有没有一种方法可以有效地做到这一点 源表 +----+---------+--------+--------+---------+ | id | fruit | price |
+----+---------+--------+--------+---------+
| 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 |
+----+----+--------+--------+--------+---------+
这里有一个方法:
;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
这里有一个方法:
;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
以下答案的前提条件是price和qty具有相同的数据类型,id是一个标识列 第一步是找到变化。您可以通过计算同一水果的所有记录(按其id排序),然后加入后续记录来实现这一点。然后可以取消打印结果并过滤掉未更改的列
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;
由于不能取消拆分多个列,因此最终选择中的情况是不可避免的。以下答案的先决条件是价格和数量具有相同的数据类型,id是标识列 第一步是找到变化。您可以通过计算同一水果的所有记录(按其id排序),然后加入后续记录来实现这一点。然后可以取消打印结果并过滤掉未更改的列
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;
由于您不能取消拆分多个列,因此最终选择中的情况不可避免。@rickythefox您可以尝试这两种解决方案,并告诉我们它们如何处理您的实际数据。@rickythefox您可以尝试这两种解决方案,并告诉我们它们如何处理您的实际数据。谢谢您的回答!谢谢你的回答!