MySQL中如何对非连续ID的连续行计算DATEDIFF时间差?
Got it, let's work through this. First, here's your raw Logs table output formatted as a clear table to visualize the expected Secs values:
| S.ID | S.INDEX | E.ID | TIME | Secs |
|---|---|---|---|---|
| 1 | 1 | 1 | 2018-05-14 16:07:48.527 | 2 |
| 2 | 1 | 1 | 2018-05-14 16:08:02.967 | 14 |
| 3 | 3 | 1 | 2018-05-14 16:08:21.750 | 19 |
| 10 | 1 | 2 | 2018-05-14 16:07:46.983 | 11 |
| 11 | 2 | 2 | 2018-05-14 16:08:00.883 | 14 |
| 12 | 3 | 2 | 2018-05-14 16:09:19.830 | 79 |
| 13 | 4 | 2 | 2018-05-14 16:09:49.907 | 30 |
| 29 | 1 | 3 | 2018-05-14 16:08:02.490 | 30 |
| 2 | 3 | 3 | 2018-05-14 16:08:06.717 | 4 |
The key issue here is that you need to:
- Group records by
E.ID - Reset the time calculation every time
S.INDEX = 1appears within anE.IDgroup
Using plain DATEDIFF won't work because it doesn't account for these reset points. Instead, we can use window functions to first create sub-groups within each E.ID (resetting on S.INDEX=1), then calculate the time difference from the previous record in the same sub-group.
Here's a SQL query that does this (works with SQL Server, PostgreSQL, MySQL 8.0+, and other databases supporting window functions):
WITH LogsSubGroups AS ( SELECT S.ID AS S_ID, S.[INDEX] AS S_INDEX, E.ID AS E_ID, TIME, -- Create a sub-group ID that increments every time S.INDEX=1 is found SUM(CASE WHEN S.[INDEX] = 1 THEN 1 ELSE 0 END) OVER (PARTITION BY E.ID ORDER BY TIME) AS SubGroupID FROM Logs ), LogsWithPreviousTime AS ( SELECT *, -- Get the TIME value from the previous record in the same E_ID and SubGroupID LAG(TIME) OVER (PARTITION BY E_ID, SubGroupID ORDER BY TIME) AS PreviousTime FROM LogsSubGroups ) SELECT S_ID, S_INDEX, E_ID, TIME, -- Calculate the seconds difference between current and previous time DATEDIFF(SECOND, PreviousTime, TIME) AS Secs FROM LogsWithPreviousTime ORDER BY E_ID, TIME;
How this works:
LogsSubGroupsCTE: We partition the data byE.IDand order byTIME. UsingSUM()with a conditional, we generate aSubGroupIDthat increases by 1 every time we hit a record whereS.INDEX=1. This effectively creates separate "chunks" of records for each reset point.LogsWithPreviousTimeCTE: TheLAG()function pulls theTIMEvalue from the immediately preceding record in the sameE_IDandSubGroupID—this is what we need to calculate the time difference against.- Final query: We use
DATEDIFFto compute the number of seconds between the current record'sTIMEand thePreviousTimefrom the sub-group.
If you're using MySQL, replace DATEDIFF(SECOND, PreviousTime, TIME) with TIMESTAMPDIFF(SECOND, PreviousTime, TIME) since MySQL's DATEDIFF only works with dates, not timestamps.
内容的提问来源于stack exchange,提问作者João Amaro

