Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL: Split events into multiple rows

Check out my SQLFiddle here (link)

In SQL Server 2008, I have table of event start and end times, like the image below.

enter image description here

I need to write a query that allows me to figure out how much of each event fell into which work shift. Our shifts are 12 hrs long and go from 06:00-18:00 and 18:00-06:00.

The query should produce results like the image below.

enter image description here

From that, I can then figure out total event durations for a particular work shift.

What can I do to go from the first image, to the second image?

like image 400
Tommy O'Dell Avatar asked Feb 20 '23 07:02

Tommy O'Dell


1 Answers

With Shifts As
  (
    Select 1 As Num
      , Cast('2012-05-01 6:00 AM' As datetime) As ShiftStart
      , DateAdd(hh,12,Cast('2012-05-01 6:00 AM' As datetime)) As ShiftEnd
    Union All
    Select Num + 1, ShiftEnd, DateAdd(hh,12,ShiftEnd)
    From Shifts
    Where ShiftEnd < '2012-05-30'
    )
  , Segments As
    (
    Select event_id
      , Case 
        When Shifts.ShiftStart > event_start Then Shifts.ShiftStart 
        Else event_start
        End As start_split_segment        
      , Case 
        When Shifts.ShiftEnd < event_end Then Shifts.ShiftEnd
        Else event_end
        End As end_split_segment          
      , Count(*) Over ( Partition By E.event_id ) As SegmentCount
    From events As E
      Join Shifts
        On E.event_start <= ShiftEnd
          And E.event_end > ShiftStart
      )
Select E.event_id, E.description, E.event_start, E.event_end
  , S.start_split_segment, S.end_split_segment
  , Case When SegmentCount > 1 Then 1 Else 0 End As is_split
  , NullIf(SegmentCount,1) As split_segments
From Segments As S
  Join events As E
    On E.event_id = S.event_id

SQL Fiddle version

In this solution, I generated a calendar of every shift's start and end date. You can extend the calendar by changing Where ShiftEnd < '2012-05-30' to a larger date. Note that if you end up with more than 50 shifts or so, you'll want to add Option(Maxrecursion 0); to end of the query to lift SQL Server's cap.

like image 127
Thomas Avatar answered Feb 28 '23 08:02

Thomas