Ben
Ben

Reputation: 187

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

Basically, I want to use system versioned tables to find out the start and end date all users held a position within a company.

I'm struggling with the amount of other changes made to the record (Other field changes that create a new versioned record). I originally tried to Group By UserId, CompanyId, Position and then take the min SysStartTime and max SysEndTime. Which at first glance did work. However it does not work if a position is changed back to its original value.

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

Focusing on UserId 1, they were an 'Assistant', then a 'Manager', then back to an 'Assistant' again. I want to get the start and end date of each of these positions reguardless of how many Other changes are made between positions.

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

I want a query that will return the following:

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

Thanks

Upvotes: 1

Views: 598

Answers (2)

Martin Smith
Martin Smith

Reputation: 454000

This should do what you need (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 

Upvotes: 1

Never Die
Never Die

Reputation: 331

You should use LAG to achieve this.

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,'')

Result

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

Upvotes: 1

Related Questions