次のデータを含むテーブルがあります。
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
連続同じステータスの行を抽出したい。たとえば、「アイドル」のユーザーが費やした時間を表示したいステータスの後に「アクティブ」ステータスが続き、 'idle' statusなど。
単一のSQLクエリでこれを行うにはどうすればよいですか?
私の望ましい出力は次のとおりです:
userID staus Duration_in_this_status (min)
------ ------------------- ------
Jason idle ---
Brown idle 5
Brown active 10
Brown idle 10
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
以下がその仕組みです。 3つの変数を定義します。 1つはグループ番号を保持し、2つはstatusおよびuserIdの前の行の値を保持します。リレーショナルデータベースでは、指定しない限り順序はありません。これは非常に重要です。 select句では、変数の値が現在の行と異なるかどうかを最初に確認します。ある場合はグループ番号をインクリメントし、ない場合はそのままにします。その後、現在の行の値を割り当てます。したがって、次の行が処理されるときに変数が評価されても、変数は前の行の値を保持します。したがって、ここでも順序は重要です。外側のクエリでは、このグループ番号でグループ化するだけで、タイムスタンプの最小値と最大値を取得できます。