Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Partition a table to get date ranges

I have a table of history for a user, and I'm trying to find date ranges that the user held a specific username. The table is an audit table that gets filled by a trigger, so it has entries every time there's a change to a user, not just to the username. I can do this to get the date range for each row:

CREATE TABLE #LoginHistory
(
  LoginHistoryID INT IDENTITY(1,1),
  LoginID INT,
  Username VARCHAR(32),
  StartDate DATETIME
)

INSERT INTO #LoginHistory (LoginID, Username, StartDate) VALUES
(1, 't', '2016-01-01'),
(1, 't', '2016-01-02'),
(1, 't', '2016-01-04'),
(1, 'test', '2016-01-05'),
(2, 't', '2016-01-08'),
(2, 'tom', '2016-01-09'),
(1, 'test', '2016-01-15'),
(1, 't', '2016-02-01')

SELECT
    LoginID,
    Username,
    StartDate,
    EndDate = LEAD(StartDate) OVER (PARTITION BY LoginID ORDER BY StartDate ASC)
FROM #LoginHistory
WHERE LoginID = 1
ORDER BY StartDate ASC

DROP TABLE #LoginHistory

Output:

LoginID  Username  StartDate                EndDate
1        t         2016-01-01 00:00:00.000  2016-01-02 00:00:00.000
1        t         2016-01-02 00:00:00.000  2016-01-04 00:00:00.000
1        t         2016-01-04 00:00:00.000  2016-01-05 00:00:00.000
1        test      2016-01-05 00:00:00.000  2016-01-15 00:00:00.000
1        test      2016-01-15 00:00:00.000  2016-02-01 00:00:00.000
1        t         2016-02-01 00:00:00.000  NULL

However, what I'd really like to do is to collapse each username duration so that there's one row per date range that a user held a username. Basically, I'm looking for this output:

LoginID  Username  StartDate                EndDate
1        t         2016-01-01 00:00:00.000  2016-01-05 00:00:00.000
1        test      2016-01-05 00:00:00.000  2016-02-01 00:00:00.000
1        t         2016-02-01 00:00:00.000  NULL

How would I go about collapsing these rows correctly?

like image 493
zimdanen Avatar asked Feb 22 '16 14:02

zimdanen


1 Answers

You can use the following query:

SELECT LoginID,
       Username,
       MIN(StartDate) AS StartDate,
       MAX(EndDate) AS EndDate
FROM (
  SELECT
      LoginID,
      Username,
      StartDate,
      EndDate = LEAD(StartDate) OVER (PARTITION BY LoginID 
                                      ORDER BY StartDate ASC),
      ROW_NUMBER() OVER (ORDER BY StartDate) -
      ROW_NUMBER() OVER (PARTITION BY LoginID, Username 
                         ORDER BY StartDate) AS grp
  FROM #LoginHistory
  WHERE LoginID = 1) AS t
GROUP BY LoginID, Username, grp
ORDER BY StartDate ASC

grp helps you identify consecutive rows having the same LoginID, Username values.

like image 157
Giorgos Betsos Avatar answered Oct 13 '22 23:10

Giorgos Betsos