use*_*749 9 mysql gaps-and-islands
我有一个包含以下数据的表:
userID tStamp status
------ ------------------- ------
Jason 2017-10-18 03:20:00 idle
Brown 2017-10-18 03:20:28 idle
Brown 2017-10-18 03:25:28 idle
Brown 2017-10-18 04:00:28 active
Brown 2017-10-18 04:10:28 active
Brown 2017-10-18 04:35:28 idle
Brown 2017-10-18 04:45:28 idle
Run Code Online (Sandbox Code Playgroud)
我想提取具有相同状态的连续行。例如,我想查看用户在 'idle' status,然后是 'active' status,然后是 'idle' status,等等所花费的时间。
如何在单个 SQL 查询中执行此操作?
我想要的输出如下:
userID staus Duration_in_this_status (min)
------ ------------------- ------
Jason idle ---
Brown idle 5
Brown active 10
Brown idle 10
Run Code Online (Sandbox Code Playgroud)
SELECT userID, status, TIMESTAMPDIFF(minute, MIN(tStamp), MAX(tStamp)) AS duration
FROM (
SELECT
t.*
, @groupNumber := IF(@prev_userID != userID OR @prev_status != status, @groupNumber + 1, @groupNumber) AS gn
, @prev_userID := userID
, @prev_status := status
FROM t
, (SELECT @groupNumber := 0, @prev_userID := NULL, @prev_status := NULL) var_init_subquery
ORDER BY userID, tStamp
) sq
GROUP BY gn, userID, status
Run Code Online (Sandbox Code Playgroud)
这是它的工作原理。我们定义了三个变量。一个保存组号,两个保存状态和用户 ID 的前一行值的值。请注意,在关系数据库中,除非您指定,否则没有顺序。这是非常重要的。在 select 子句中,我们首先检查变量值是否与当前行不同。如果是,我们增加组号,如果不是,我们保持原样。之后,我们分配当前行的值。因此,在处理下一行时评估变量时,它们仍保留前一行的值。所以这里的顺序也很重要。在外部查询中,我们只需按此组号进行分组即可获得时间戳的最小值和最大值。
| 归档时间: |
|
| 查看次数: |
7253 次 |
| 最近记录: |