MySQL 5.6中如何计算分组数据的时间差
Calculate Time Difference Between START and END Events per Session
Got it, let's work through calculating the time difference between each paired START and END event for your session_id groups. Looking at your data, some sessions have multiple cycles of START → END, so we need to make sure we pair each start event with its corresponding end correctly.
First, let's recap your source data for clarity:
| id | session_id | event | created |
|---|---|---|---|
| 1 | 101 | START | 2010-01-10 09:30:10 |
| 2 | 102 | START | 2010-01-10 09:31:10 |
| 3 | 101 | END | 2010-01-10 09:32:10 |
| 4 | 103 | START | 2010-01-10 09:35:10 |
| 5 | 102 | END | 2010-01-10 09:38:10 |
| 6 | 103 | END | 2010-01-10 09:39:10 |
| 7 | 101 | START | 2010-01-10 09:39:10 |
| 8 | 102 | START | 2010-01-10 09:42:10 |
| 9 | 103 | START | 2010-01-10 09:39:10 |
| 10 | 102 | END | 2010-01-10 09:45:10 |
Solution Using Window Functions (Works in PostgreSQL, MySQL 8+, SQL Server, etc.)
We'll use a common table expression (CTE) to group each START-END pair together, then calculate the time difference for each group.
WITH session_event_groups AS ( SELECT session_id, event, created, -- Assign a unique group number to each START-END pair SUM(CASE WHEN event = 'START' THEN 1 ELSE 0 END) OVER ( PARTITION BY session_id ORDER BY created ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS pair_group FROM your_table_name -- Replace with your actual table name ) SELECT session_id, pair_group, -- Calculate time difference between END and START MAX(CASE WHEN event = 'END' THEN created END) - MAX(CASE WHEN event = 'START' THEN created END) AS session_duration, -- Optional: Get duration in minutes for readability (adjust unit as needed) TIMESTAMPDIFF(MINUTE, MAX(CASE WHEN event = 'START' THEN created END), MAX(CASE WHEN event = 'END' THEN created END) ) AS duration_minutes FROM session_event_groups GROUP BY session_id, pair_group ORDER BY session_id, pair_group;
How This Works:
- CTE (
session_event_groups): TheSUMwindow function increments a counter every time it hits aSTARTevent for a session. This creates apair_groupnumber that ties eachSTARTto all subsequent events until the nextSTART(including its matchingEND). - Main Query: We group by
session_idandpair_group, then useMAXto pull theSTARTandENDtimestamps for each group. Subtracting these gives the duration of that session cycle.
Sample Output:
| session_id | pair_group | session_duration | duration_minutes |
|---|---|---|---|
| 101 | 1 | 00:02:00 | 2 |
| 101 | 2 | NULL | NULL |
| 102 | 1 | 00:07:00 | 7 |
| 102 | 2 | 00:03:00 | 3 |
| 103 | 1 | 00:04:00 | 4 |
| 103 | 2 | NULL | NULL |
Note: NULL values appear for sessions where a START doesn't have a matching END yet (like session 101's second start and session 103's second start).
Handling Edge Cases
- If you want to exclude unpaired events, add a
HAVINGclause to the main query:HAVING MAX(CASE WHEN event = 'END' THEN created END) IS NOT NULL - For databases that don't support window functions (older MySQL versions), you can use correlated subqueries to find the next
ENDfor eachSTART, but window functions are much more efficient.
内容的提问来源于stack exchange,提问作者Ravi Gohil
相关产品推荐
相关产品推荐

