我有许多连接的“系统版本”表,例如人,电话号码和电子邮件地址 此人一次只能拥有一个电话号码和一个电子邮件地址。
通常不会在一次同时更新所有3个交易的事务之外通常更新PhoneNumber和EmailAddress。 (但是 可以独立更新,只是在正常情况下不可以) 例如。如果我更改电话号码,则将在同一笔交易中向所有3条记录发送更新,因此在历史记录表中为它们提供相同的“开始时间”。
假设我插入一个人,然后在2笔交易中更改了该人的姓名,电子邮件地址和电话号码:
DECLARE @Id TABLE(ID INT)
DECLARE @PersonId INT
-- Initial insert
BEGIN TRANSACTION
INSERT INTO Person (Name) OUTPUT inserted.PersonId INTO @Id VALUES ('Homer')
SELECT @PersonId = Id FROM @Id
INSERT INTO EmailAddress (Address, PersonId) VALUES ('homer@fake', @PersonId)
INSERT INTO PhoneNumber (Number, PersonId) VALUES ('999', @PersonId)
COMMIT TRANSACTION
-- Update
WAITFOR DELAY '00:00:02'
BEGIN TRANSACTION
UPDATE Person SET Name = 'Kwyjibo' WHERE PersonID = @PersonId
UPDATE EmailAddress SET Address = 'kwyjibo@fake' WHERE PersonID = @PersonId
UPDATE PhoneNumber SET Number = '000' WHERE PersonID = @PersonId
COMMIT TRANSACTION
现在,我使用时间查询从视图(只是表的内部联接)中进行选择:
SELECT * FROM vwPerson FOR SYSTEM_TIME ALL
WHERE PersonId = @PersonId
ORDER BY SysStartTime DESC
对于每种编辑组合,我都会返回一行!
如何查询此视图(如果可能的话),以仅返回1行以获取同一事务中进行的更新?
我可以添加一个WHERE子句以匹配所有SysStartTimes,但这将排除那些表独立于其他2个更新的情况。
答案 0 :(得分:0)
由于有独立的更新,因此您实际上首先必须“重建”时间轴,可以将数据加入到该时间轴中。接下来是“草图”,显然您的实际表定义没有经过如此测试:
;WITH AllTimes as (
SELECT PersonId,SysStartTime as ATime FROM Person
UNION
SELECT PersonId,SysEndTime FROM Person
UNION
SELECT PersonId,SysStartTime FROM EmailAddress
UNION
SELECT PersonId,SysEndTime FROM EmailAddress
UNION
SELECT PersonId,SysStartTime FROM PhoneNumber
UNION
SELECT PersonId,SysEndTime FROM PhoneNumber
), Ordered as (
SELECT
PersonId, ATime, ROW_NUMBER() OVER (PARTITION BY PersonId ORDER BY Atime) rn
FROM
AllTimes
), Intervals as (
SELECT
p1.PersonId,
o1.ATime as StartTime,
o2.ATime as EndTime
FROM
Ordered o1
inner join
Ordered o2
on
o1.PersonId = o2.PersonId and
o1.rn = o2.rn - 1
)
SELECT
* --TODO - Columns
FROM
Intervals i
inner join
Person p
on
i.PersonId = p.PersonId and
i.StartTime < p.SysEndTime and
p.SysStartTime < i.EndTime
inner join
Email e
on
i.PersonId = e.PersonId and
i.StartTime < e.SysEndTime and
e.SysStartTime < i.EndTime
inner join
PhoneNumber pn
on
i.PersonId = pn.PersonId and
i.StartTime < pn.SysEndTime and
pn.SysStartTime < i.EndTime
如果您只想提供一个人的详细信息,则使用适当的过滤器,优化器有望将其解决。对于我也错过了的联接,可能还有其他过滤器。
希望您能看到3个CTE如何构建时间表。我们利用UNION
消除了第一个重复项。