Reputation: 5851
I have source of data in the following format:
Event Type| Date
1 | 2011-07-14 09:00
1 | 2011-07-14 09:01
1 | 2011-07-14 09:02
2 | 2011-07-14 09:30
2 | 2011-07-14 09:31
1 | 2011-07-14 10:00
1 | 2011-07-14 10:01
Event types are sorted by date, as they occurred. I need to make a query which will show the date ranges when events were used, sorted by date. Like this:
Event Type | Date Range
1 | 2011-07-14 09:00 - 2011-07-14 09:02
2 | 2011-07-14 09:30 - 2011-07-14 09:31
1 | 2011-07-14 10:00 - 2011-07-14 10:01
Do you have any hints? I reckon this will probably need to be done with analytic functions, but I haven't been able to come up with a decent solution yet.
Upvotes: 1
Views: 57
Reputation: 77657
You could also try the following approach:
WITH ranked AS (
SELECT
EventType,
Date,
ROW_NUMBER() OVER (ORDER BY Date) -
ROW_NUMBER() OVER (PARTITION BY EventType ORDER BY Date) AS GroupID
FROM Events
)
SELECT
EventType,
MIN(Date) AS StartDate,
MAX(Date) AS EndDate
FROM ranked
GROUP BY
GroupID,
EventType
ORDER BY
MIN(Date)
Upvotes: 2
Reputation: 86706
I'm sure there is a better solution, but what about this?
WITH
ordered_data AS
(
SELECT ROW_NUMBER() OVER (ORDER BY Date) AS row_id, * FROM event_data
),
[start_events] AS
(
SELECT * FROM ordered_data AS [start]
WHERE NOT EXISTS (SELECT * FROM ordered_data WHERE row_id = [start].row_id - 1 AND event_type = [start].event_type)
),
[end_events] AS
(
SELECT * FROM ordered_data AS [end]
WHERE NOT EXISTS (SELECT * FROM ordered_data WHERE row_id = [end].row_id + 1 AND event_type = [end].event_type)
)
SELECT
*
FROM
[start_events]
INNER JOIN
[end_events]
ON [end_events].row_id = (SELECT MIN(row_id) FROM [end_events] WHERE row_id >= [start_events].row_id)
This should also cope with scenarios where the 'group' only has one event in it; Such as (1, 1, 2, 1, 1)
Upvotes: 1