Home > database >  Transforming corresponding Start-Stop Time in rows to columns
Transforming corresponding Start-Stop Time in rows to columns

Time:12-31

I have a table in this format:

User Time status
User 1 2021-12-24 14:00:00 connect
User 2 2021-12-24 14:05:23 connect
User 2 2021-12-24 14:10:11 disconnect
User 2 2021-12-24 14:10:17 connect
User 1 2021-12-24 19:35:22 disconnect
User 2 2021-12-25 01:10:40 disconnect

I'd like to have a table with connect & disconnect as columns, one row for each session from connect to next disconnect per user

User connect disconnect
User 1 2021-12-24 14:00:00 2021-12-24 19:35:22
User 2 2021-12-24 14:05:23 2021-12-24 14:10:11
User 2 2021-12-24 14:10:17 2021-12-25 01:10:40

I could create this on MySQL, MariaDB or MSSQL, depending on where it's easier to do. Is it possible to do as a view? Great addon, but not absolutely necessary: column "duration" that shows the duration of each session from connect to disconnect.

If easier, connect/disconnect times could be (mili)seconds from 1970/1/1.

CodePudding user response:

Try the following solution, it should work in most RDBMS, being careful to correctly delimit column names that clash with reserved words.

First you need to pair up the connects/disconnects, this can be done by numbering the rows and then duplicating every-other number using a modulo, then using conditional aggregation:

with rn as (
  select *, 
    Row_Number() over(partition by user order by time) rn
  from t
), gp as (
  select *, 
    case when rn %2=0 then
      Lag(rn) over(partition by user order by rn) 
    else rn end gp
  from rn
)
select 
    [user], 
    Max(case when status = 'connect' then time end) Connect,
    Max(case when status = 'disconnect' then time end) Disconnect
from gp
group by user, gp

CodePudding user response:

The Conditional Aggregation can be used after applying ROW_NUMBER() window function if your available databases' versions are 8.0 , 10.2 and 2005 for MySQL, MariaDB and SQL Server respectively such as

WITH t2 AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY user,status ORDER BY time) AS rn,
       t.*
  FROM t     
)
SELECT User, 
       MAX(CASE WHEN status = 'connect' THEN time END) AS connect,
       MAX(CASE WHEN status = 'disconnect' THEN time END) AS disconnect
  FROM t2
 GROUP BY user, rn
 ORDER BY user, rn

where

  • the dataset is grouped by user and status columns while sorted by time column

  • user, which's a reserved keyword, must be replaced by [user] as a column name for SQL Server DB

Demo for MySQL/MariaDB

Demo for SQL Server

  • Related