Home > database >  Create sql Key based on datetime that is persistent overnight
Create sql Key based on datetime that is persistent overnight

Time:07-22

I have a time series with a table like this

CarId           
EventDateTime
Event
SessionFlag
CarId EventDateTime Event SessionFlag ExpectedKey
1 2022-01-01 7:00 Start 1 1-20220101-7
1 2022-01-01 7:05 Drive 1 1-20220101-7
1 2022-01-01 8:00 Park 1 1-20220101-7
1 2022-01-01 10:00 Drive 1 1-20220101-7
1 2022-01-01 18:05 End 0 1-20220101-7
1 2022-01-01 23:00 Start 1 1-20220101-23
1 2022-01-01 23:05 Drive 1 1-20220101-23
1 2022-01-02 2:00 Park 1 1-20220101-23
1 2022-01-02 3:00 Drive 1 1-20220101-23
1 2022-01-02 15:00 End 0 1-20220101-23
1 2022-01-02 16:00 Start 1 1-20220102-16

Other CarIds do exist. What I am attempting to do is create the last column, ExpectedKey.

The problem I face though is midnight, as the same session can exist over two days. The record above with ExpectedKey 1-20220101-23 is the prime example of what I'm trying to achieve.

I've played with using:

CASE 
     WHEN SessionFlag<> 0 
     AND 
     SessionFlag= LAG(SessionFlag) OVER (PARTITION BY Carid ORDER BY EventDateTime) 
THEN FIRST_VALUE(CarId '-' Convert(CHAR(8),EventDateTime,112) '-' CAST(DATEPART(HOUR,EventDateTime)AS            
    VARCHAR))OVER (PARTITION BY CarId ORDER BY EventDateTime)
ELSE CarId '-' Convert(CHAR(8),EventDateTime,112) '-' CAST(DATEPART(HOUR,EventDateTime)AS VARCHAR) END AS SessionId

But can't seem to make it partition correctly overnight.

Can anyone off advice?

CodePudding user response:

using APPLY to get the Start event datetime and form the key with concat_ws

select *
from   time_series t
       cross apply
       (
          select top 1 
                 ExpectedKey = concat_ws('-', 
                                         CarId, 
                                         convert(varchar(10), EventDateTime, 112), 
                                         datepart(hour, EventDateTime))
          from   time_series x
          where  x.Event = 'Start'
          and    x.EventDateTime <= t.EventDateTime
          order by x.EventDateTime desc
       ) k

CodePudding user response:

This is a classic gaps-and-islands problem. There are a number of solutions.

The simplest (if not that efficient) is partitioning over a windowed conditional count

WITH Groups AS (
    SELECT *,
      GroupId = COUNT(CASE WHEN t.Event = 'Start' THEN 1 END)
        OVER (PARTITION BY t.CarId ORDER BY t.EventDateTime)
    FROM YourTable t
)
SELECT *,
  NewKey = CONCAT_WS('-',
    t.CarId,
    CONVERT(varchar(8), EventDateTime, 112),
    FIRST_VALUE(DATEPART(hour, t.EventDateTime))
      OVER (PARTITION BY t.CarId, t.GroupId ORDER BY t.EventDateTime
            ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
  )
FROM Groups t;

db<>fiddle

  • Related