【发布时间】:2017-11-28 00:41:01
【问题描述】:
我有一个 SQL Azure 表,并且我打开了新的临时表功能(SQL Server 2016 和 SQL Azure v12 的新功能)。此功能创建另一个表来跟踪对主表的所有更改(我在问题的底部包含了指向有关时态表的文档的链接)。您可以使用特殊查询语言来获取此历史记录。 请注意以下查询中的 FOR SYSTEM_TIME ALL:
SELECT
ValidFrom
, ValidTo
, ShiftId
, TradeDate
, StatusID
, [LastActionDate]
, [OwnerUserID]
, [WorkerUserID]
, [WorkerEmail]
, [Archived]
FROM [KrisisShifts_ShiftTrade]
FOR SYSTEM_TIME ALL
WHERE [ShiftID] = 27
ORDER BY ValidTo Desc
结果集如下所示:
ValidFrom ValidTo ShiftId TradeDate StatusID LastActionDate OwnerUserID WorkerUserID WorkerEmail Archived
--------------------------- --------------------------- ----------- ---------- ----------- ----------------------- ----------- ------------ -------------------------------------------------- --------
2017-06-21 00:26:44.51 9999-12-31 23:59:59.99 27 2017-01-27 3 2017-01-09 16:23:39.760 45 34 test@hotmail.com 1
2017-06-21 00:19:35.57 2017-06-21 00:26:44.51 27 2017-01-27 2 2017-01-09 16:23:39.760 45 34 test@hotmail.com 1
2017-06-21 00:19:16.25 2017-06-21 00:19:35.57 27 2017-01-28 3 2017-01-09 16:23:39.760 45 34 test@hotmail.com 1
使用SYSTEM_TIME FOR ALL临时表从主表返回当前记录,这是第一个,其余记录是存储在跟踪表中的该记录的先前版本。 (可以看到validFrom和ValidTo列,很明显时间记录就是当前记录)在这种情况下,保存历史记录的跟踪表称为KrisisShifts_ShiftTrade_History
我想要什么:
我想构建一个查询,仅突出显示在每个历史点所做的更改。 请注意,第二条记录具有不同的 StatusID,而第三条记录具有不同的 TradeDate
我想生成一个如下所示的结果集(我想我会忽略第一条或当前记录,因为它显然没有被更改):
期望的结果:
ShiftId Column Value ValidFrom ValidTo
---------- ------------- ------------------- --------------------------- --------------------------
27 StatusId 2 2017-06-21 00:19:35.57 2017-06-21 00:26:44.51
27 TradeDate 2017-01-28 2017-06-21 00:19:35.57 2017-06-21 00:26:44.51
我不知道如何做到这一点。或者我对另一种解决方案持开放态度。我希望能够快速查看每条记录与原始记录相比的更改。
我试图取消透视结果以比较它们,但我无法让它工作,因为每一行的班次 ID 都是相同的。我很想在这里展示更多的作品,但我真的被困住了。
编辑 1:
我已经能够使用 lag() 隔离以下查询中仅一列的更改。我可以将这个查询与我想要跟踪的每一列的类似查询联合起来,但是,这是很多工作并且必须为每个表构建。有没有办法动态执行此操作,以便自动检测列?
StatusID 更改历史查询:(我将记录隔离到 27 的 shiftId 仅用于测试)
SELECT 'SHIFT STATUS' as ColumnName, t1.RecVersion, t1.ShiftID, t1.ValidFrom, t1.ValidTo, t1.StatusId
, (SELECT [Title] FROM [dbo].[KrisisShifts_Status] WHERE [dbo].[KrisisShifts_Status].[StatusID] = t1.StatusId) AS RecStatus
FROM
(SELECT TOP 100 PERCENT
ROW_NUMBER() OVER(PARTITION BY ShiftId ORDER BY ValidTo ASC) AS RecVersion -- reverse sorting the ValidTo date gives "version count" to column changes
, t2.ValidTo
, t2.ValidFrom
, t2.ShiftID
, t2.StatusId
, LAG(StatusId,1,0) OVER (ORDER BY ValidTo DESC) AS PrevStatusId
FROM [KrisisShifts_ShiftTrade]
FOR SYSTEM_TIME ALL AS t2
ORDER BY t2.ValidTo Desc
) AS t1
WHERE
(t1.StatusId <> t1.PrevStatusId)
AND
SHIFTID = 27
ORDER BY t1.ValidTo DESC
查询结果:
ColumnName RecVersion ShiftID ValidFrom ValidTo StatusId RecStatus
------------ -------------------- ----------- --------------------------- --------------------------- ----------- --------------------------------------------------
SHIFT STATUS 3 27 2017-06-21 00:26:44.51 2017-06-25 14:09:32.37 3 Confirmed
SHIFT STATUS 2 27 2017-06-21 00:19:35.57 2017-06-21 00:26:44.51 2 Reserved
SHIFT STATUS 1 27 2017-06-21 00:19:16.25 2017-06-21 00:19:35.57 3 Confirmed
结束编辑 1:
问题:
有人可以帮我将时态表结果集中每个 shiftId 的列中更改的数据与之前的记录隔离吗?
提前致谢
编辑#2:
以下是我想从这个表中“观察变化”的所有列的列表:
[交易日期] [状态ID] [最后行动日期] [AllowedRankID] [所有者用户 ID] [所有者电子邮件] [所有者位置 ID] [所有者等级 ID] [所有者雇员 ID] [工人用户 ID] [工人电子邮件] [工人位置 ID] [工人等级 ID] [工人排号] [工人雇员ID] [IsPartialShift] [细节] [LastModifiedByUserID] [存档] [更新日期]
结束编辑 2:
关于新标签的说明:
我为临时表创建了一个新标签,因为没有标签。如果有更多声誉的人想将其添加到标签的详细信息中,以下有它们的描述。
【问题讨论】:
-
shiftID 似乎永远不会改变,你确定你说的不是 statusID?
-
我认为您只想使用 Lag() 并根据您声明的输出请求比较值。
-
ShiftId 是表的主键
-
除非你想弄乱游标(请不要),我建议你做这个客户端。
-
关系型 DBMS(例如 SQL Server)假定架构稳定。这意味着您必须在查询中显式写入列名。编写适用于任何表的通用代码的唯一方法是使用来自
INFORMATION_SCHEMA系统视图(或此类视图的非标准 SQL Server 特定版本)的元数据动态构建查询文本,然后执行它,比如说,sp_executesql。
标签: sql sql-server tsql azure-sql-database temporal-tables