选择具有相同值的“连续”行

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)

tom*_*bom 5

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 子句中,我们首先检查变量值是否与当前行不同。如果是,我们增加组号,如果不是,我们保持原样。之后,我们分配当前行的值。因此,在处理下一行时评估变量时,它们仍保留前一行的值。所以这里的顺序也很重要。在外部查询中,我们只需按此组号进行分组即可获得时间戳的最小值和最大值。

  • 在此处阅读有关用户定义变量的更多信息