SQL 使用系统版本表查询 select 值的开始和结束日期时间

SQL query to select the start and end datetime of a value with system versioned tables

基本上,我想使用系统版本表来找出所有用户在公司内担任职位的开始和结束日期。

我正在努力处理对记录所做的其他更改量(Other 创建新版本记录的字段更改)。 我最初尝试按 UserIdCompanyIdPosition 分组,然后取最小值 SysStartTime 和最大值 SysEndTime。乍一看确实有效。但是,如果将位置更改回其原始值,则它不起作用。

SELECT DISTINCT 
    cu.UserId, 
    cu.CompanyId, 
    cu.Position,
    MIN(cu.SysStartTime) AS StartTime,
    MAX(cu.SysEndTime) AS EndTime
FROM dbo.CompanyUser FOR SYSTEM_TIME ALL cu
GROUP BY cu.UserId, cu.CompanyId, cu.Position

关注 UserId 1,它们是 'Assistant',然后是 'Manager',然后又回到 'Assistant'。我想获得每个职位的开始和结束日期,而不管职位之间进行了多少 Other 更改。

UserId     CompanyId     Position      Other     SysStartTime             SysEndTime
--------   -----------   -----------   -------   ----------------------   ---------------------
1          1             Assistant     A         2019-12-01 13:00:00      2019-12-01 14:00:00
2          1             Manager       A         2019-12-01 13:00:00      2019-12-01 20:00:00
1          1             Assistant     B         2019-12-01 14:00:00      2019-12-01 17:00:00
1          1             Manager       A         2019-12-01 17:00:00      2019-12-01 20:00:00
2          1             Executive     A         2019-12-01 20:00:00      9999-12-31 23:59:59
3          1             CEO           A         2019-12-01 13:00:00      9999-12-31 23:59:59
1          1             Assistant     A         2019-12-01 20:00:00      9999-12-31 23:59:59

我想要一个将 return 以下内容的查询:

UserId     CompanyId     Position      SysStartTime             SysEndTime
--------   -----------   -----------   ----------------------   ---------------------
1          1             Assistant     2019-12-01 13:00:00      2019-12-01 17:00:00
2          1             Manager       2019-12-01 13:00:00      2019-12-01 20:00:00
1          1             Manager       2019-12-01 17:00:00      2019-12-01 20:00:00
2          1             Executive     2019-12-01 20:00:00      9999-12-31 23:59:59
3          1             CEO           2019-12-01 13:00:00      9999-12-31 23:59:59
1          1             Assistant     2019-12-01 20:00:00      9999-12-31 23:59:59

谢谢

您应该使用 LAG 来实现。

SELECT UserId, CompanyId, Position, StartTime, EndTime
FROM
(
   SELECT DISTINCT 
      cu.UserId, 
      cu.CompanyId, 
      cu.Position,
      LAG(cu.Position) OVER(PARTITION BY cu.UserId,cu.Position ORDER BY (SELECT NULL)) NextPosition
      MIN(cu.SysStartTime) AS StartTime,
      MAX(cu.SysEndTime) AS EndTime
FROM dbo.CompanyUser FOR SYSTEM_TIME ALL cu
GROUP BY cu.UserId, cu.CompanyId, cu.Position
)T 
WHERE Position <> ISNULL(NextPosition,'')

结果

UserId     CompanyId     Position      SysStartTime             SysEndTime
--------   -----------   -----------   ----------------------   ---------------------
1          1             Assistant     2019-12-01 13:00:00      2019-12-01 17:00:00
2          1             Manager       2019-12-01 13:00:00      2019-12-01 20:00:00
1          1             Manager       2019-12-01 17:00:00      2019-12-01 20:00:00
2          1             Executive     2019-12-01 20:00:00      9999-12-31 23:59:59
3          1             CEO           2019-12-01 13:00:00      9999-12-31 23:59:59
1          1             Assistant     2019-12-01 20:00:00      9999-12-31 23:59:59

这应该可以满足您的需求 (Fiddle)。

WITH T
     AS (SELECT *,
                LAG(Position) OVER (PARTITION BY UserId ORDER BY SysStartTime) AS PrevPosition
         FROM dbo.CompanyUser FOR SYSTEM_TIME ALL cu)
SELECT UserId,
       CompanyId,
       Position,
       Other,
       SysStartTime,
       SysEndTime = LEAD(SysStartTime, 1, SysEndTime) OVER (PARTITION BY UserId ORDER BY SysStartTime)
FROM   T
WHERE  EXISTS (SELECT PrevPosition
               EXCEPT
               SELECT Position)
ORDER  BY UserId,
          SysStartTime