如何利用System Versioned Tables获取用户各职位分段的起止时间
Correct SQL Query to Get Position History with System Versioned Tables (Handling Reverted Positions)
Got it, I see exactly where your original approach fell short—grouping directly by UserId, CompanyId, and Position merges all identical roles for a user together, even when they’re separated by a different position in between. That’s why User 1’s reverted Assistant role wasn’t showing up as a distinct segment. Let’s fix this with a window function-based solution that tracks consecutive position periods.
Sample Data
| 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 |
Correct SQL Query
WITH RankedPositions AS ( SELECT UserId, CompanyId, Position, SysStartTime, SysEndTime, -- Create a unique group ID for each consecutive position segment SUM(CASE WHEN prev_position = Position THEN 0 ELSE 1 END) OVER (PARTITION BY UserId, CompanyId ORDER BY SysStartTime) AS position_group FROM ( SELECT UserId, CompanyId, Position, SysStartTime, SysEndTime, -- Fetch the previous position for the same user/company to detect changes LAG(Position) OVER (PARTITION BY UserId, CompanyId ORDER BY SysStartTime) AS prev_position FROM dbo.CompanyUser FOR SYSTEM_TIME ALL ) AS position_history ) SELECT UserId, CompanyId, Position, MIN(SysStartTime) AS SysStartTime, MAX(SysEndTime) AS SysEndTime FROM RankedPositions GROUP BY UserId, CompanyId, Position, position_group ORDER BY UserId, CompanyId, SysStartTime;
How This Works
- Inner Subquery (
position_history): Uses theLAG()window function to pull the position from the immediately preceding version for each user/company, ordered bySysStartTime. This lets us check if the current position is the same as the last one. - CTE (
RankedPositions): Creates aposition_groupvalue. Every time the position changes from the previous row, we increment the group ID. This groups together all consecutive rows where the user held the same position (even if other fields likeOtherwere modified). - Final SELECT: Groups by
UserId,CompanyId,Position, andposition_group—this ensures we only merge identical positions that are consecutive, not all identical positions across the user’s history. We then take the minimum start time and maximum end time for each group to get the full duration of that position segment.
Expected Output
| UserId | CompanyId | Position | SysStartTime | SysEndTime |
|---|---|---|---|---|
| 1 | 1 | Assistant | 2019-12-01 13:00:00 | 2019-12-01 17:00:00 |
| 1 | 1 | Manager | 2019-12-01 17:00:00 | 2019-12-01 20:00:00 |
| 1 | 1 | Assistant | 2019-12-01 20:00:00 | 9999-12-31 23:59:59 |
| 2 | 1 | Manager | 2019-12-01 13: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 |
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

