SQL 使用系统版本表查询 select 值的开始和结束日期时间
SQL query to select the start and end datetime of a value with system versioned tables
基本上,我想使用系统版本表来找出所有用户在公司内担任职位的开始和结束日期。
我正在努力处理对记录所做的其他更改量(Other
创建新版本记录的字段更改)。
我最初尝试按 UserId
、CompanyId
、Position
分组,然后取最小值 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
基本上,我想使用系统版本表来找出所有用户在公司内担任职位的开始和结束日期。
我正在努力处理对记录所做的其他更改量(Other
创建新版本记录的字段更改)。
我最初尝试按 UserId
、CompanyId
、Position
分组,然后取最小值 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