2017-05-04 11 views
3

モバイルデバイス上のユーザーに関するステータス更新を含むテーブルがあります。彼らは、ステータスを変更したり、自分の位置が更新され、新しい行が作成されるたびに私がやろうとしていますSQLは2つの特定の値のみを含む2つの行の時間差を計算します

view_id time_stamp   user   issue_event  original_value new_value 
----------------------------------------------------------------------------------------- 
6040462 2017-03-20 02:00:43 DerekRoberts Position updated NULL    NULL 
6040461 2017-03-20 02:04:01 JamesMorrison state changed  Active   Paused 
6040461 2017-03-20 02:08:33 JamesMorrison Position updated NULL    NULL 
6040462 2017-03-20 02:20:42 DerekRoberts Position updated NULL    NULL 
6040462 2017-03-20 02:32:29 DerekRoberts state changed  Active   Paused 
6040461 2017-03-20 02:34:11 JamesMorrison state changed  Paused   Active 
6040461 2017-03-20 02:36:22 JamesMorrison Position updated NULL    NULL 
6040462 2017-03-20 02:52:47 DerekRoberts Position updated NULL    NULL 
6040462 2017-03-20 03:01:03 DerekRoberts state changed  Paused   Active 

何が各ユーザーがための「一時停止」状態にとどまる時間の長さを見つけることです...これは、[一時停止]値と[新規値]列の[アクティブ]値の間の時間差です。ユーザーごとに

LEAD()を使用して各ユーザーの次の行を見つけることができると考えましたが、一時停止した時間の終了を示す「アクティブ」はめったに次の行ではありません。テーブルを下ろす。

これまでのところ、私のクエリは次のようになります。これを返す

;WITH UserPauseActivity AS 
(SELECT [new_value], 
ShiftDate = CAST([time_stamp] as DATE), 
PauseStartUser = [user], 
PauseEndUser = LEAD([user], 1) OVER(ORDER BY [user], [time_stamp]), 
PauseStart = [time_stamp], 
PauseEnd = LEAD([time_stamp], 1) OVER(ORDER BY [user], [time_stamp]), 
PauseStartDate = CAST([time_stamp] AS DATE), 
PauseEndDate = CAST(LEAD([time_stamp], 1) OVER(ORDER BY [user], [time_stamp]) AS DATE) 
FROM [SAFE].[dbo].[cc_shift_log_view]) 

SELECT PauseStartUser [user], 
ShiftDate, 
PauseStart, 
PauseEnd, 
DATEDIFF(minute, PauseStart, PauseEnd) IdleTime 
FROM UserPauseActivity 
WHERE [new_value] = 'Paused' 
AND PauseEnd IS NOT NULL 
AND PauseStartUser = PauseEndUser 
AND PauseStartDate = PauseEndDate 
AND PauseStartDate >= '2017-03-20 00:00:00' and PauseStartDate <= '2017-03-21 23:59:59' 
ORDER BY ShiftDate, [user] 

user    ShiftDate PauseStart   PauseEnd    IdleTime 
--------------------------------------------------------------------------------- 
JamesMorrison 2017-03-20 2017-03-20 02:04:01 2017-03-20 02:08:33 4 
DerekRoberts  2017-03-20 2017-03-20 02:32:29 2017-03-20 02:52:47 20 

PauseStart値が正しいですが、PauseEndは適切ではない、の次の行であることその一時停止期間の実際の終了を示す対応する「アクティブ」値を引き継ぐ次の行ではなく、そのユーザーのためのテーブルを作成します。

私はMS SQL Serverを使用しています2012年

+0

複数の一時停止がある場合、ユーザーに複数の行が必要ですか? –

+0

私は、LEADを使用することができます、あなたがどこにいるのか、あなたのサブクエリーを正しく注文すると思います。次の行だけが十分なフィルタリングと順序付けを持つ正しいものになることは可能です。 –

+0

要するに - はい。対応するActiveがなければ、2つの連続した一時停止が存在することは不可能です。デバイスでは一時停止を選択し、一時停止状態からの唯一の選択肢はアクティブに戻ります。だから、たとえ数時間後であっても、「一時停止」のたびに「アクティブ」が常に存在します。 –

答えて

1

可能のみ状態変化がアクティブであるという仮定の下で - >一時停止 - >アクティブ...、あなたが希望解像度を得るためにleadを使用することができますウルトラ。

select usr,shiftDate,pause_start,pause_end,datediff(second,pause_start,pause_end)/60.0 as idleTime 
from (select usr,cast(time_stamp as date) as shiftDate,time_stamp as pause_start 
     ,lead(time_stamp) over(partition by usr order by time_stamp) as pause_end 
     ,original_value,new_value 
     from t 
     where issue_event='state changed' 
    ) t 
where original_value='Active' and new_value='Paused'  
+0

これは完璧です!まさに私が達成しようとしていたもの...多くのありがとう! :) –

0
あなたが一時停止し、以下のように積極的に一時停止するアクティブから一つだけの変更がありますピボットを使用して、あなたを想定し、この結果を得ることができます

select view_id, [user], [1] as [PauseStart], [2] as [PauseEnd], IdleTime = Datediff(MINUTE, [1],[2]) from (
select view_id, time_stamp, [user], RowN = Row_Number() over (partition by [user] order by time_stamp) from #youruser 
where issue_event = 'state changed ' 
) a 
pivot (max(time_stamp) for RowN in ([1],[2])) p 

出力:

+---------+---------------+-------------------------+-------------------------+----------+ 
| view_id |  user  |  PauseStart  |  PauseEnd   | IdleTime | 
+---------+---------------+-------------------------+-------------------------+----------+ 
| 6040462 | DerekRoberts | 2017-03-20 02:32:29.000 | 2017-03-20 03:01:03.000 |  29 | 
| 6040461 | JamesMorrison | 2017-03-20 02:04:01.000 | 2017-03-20 02:34:11.000 |  30 | 
+---------+---------------+-------------------------+-------------------------+----------+ 
0

サブクエリーを使用したOUTER APPLY(下の例)も可能です。完了していない休止を捕らえたくない場合は、「OUTER APPLY」を「CROSS APPLY」に変更します。

CREATE TABLE #Table (
    view_id int, 
    time_stamp DateTime, 
    [user] nvarchar(50), 
    issue_event nvarchar(50), 
    original_value nvarchar(30), 
    new_value nvarchar(40)) 

INSERT INTO #Table 
VALUES 
(6040462,'2017-03-20 02:00:43','DerekRoberts','Position updated',NULL,NULL) 
,(6040461,'2017-03-20 02:04:01','JamesMorrison','state changed','Active','Paused') 
,(6040461,'2017-03-20 02:08:33','JamesMorrison','Position updated',NULL,NULL) 
,(6040462,'2017-03-20 02:20:42','DerekRoberts','Position updated',NULL,NULL) 
,(6040462,'2017-03-20 02:32:29','DerekRoberts','state changed','Active','Paused') 
,(6040461,'2017-03-20 02:34:11','JamesMorrison','state changed','Paused','Active') 
,(6040461,'2017-03-20 02:36:22','JamesMorrison','Position updated',NULL,NULL) 
,(6040462,'2017-03-20 02:52:47','DerekRoberts','Position updated',NULL,NULL) 
,(6040462,'2017-03-20 03:01:03','DerekRoberts','state changed','Paused','Active') 
,(6040462,'2017-03-21 03:32:29','DerekRoberts','state changed','Active','Paused') 
,(6040462,'2017-03-21 04:05:03','DerekRoberts','state changed','Paused','Active') 
,(6040461,'2017-03-22 02:04:01','JamesMorrison','state changed','Active','Paused') 


SELECT 
    * 
FROM 
    #Table 

SELECT 
    [user], 
    CONVERT(nvarchar(10), pausedEvent.time_stamp, 102) ShiftDate, 
    pausedEvent.time_stamp PauseStart, 
    activatedEvent.time_stamp PauseEnd, 
    DATEDIFF(minute, pausedEvent.time_stamp, activatedEvent.time_stamp) IdleTime 
FROM 
    #Table pausedEvent 
    OUTER APPLY (
     SELECT TOP 1 
      activatedEvent.time_stamp 
     FROM 
      #Table activatedEvent 
     WHERE 
      activatedEvent.issue_event = 'state changed' 
      and activatedEvent.original_value = 'Paused' 
      and activatedEvent.new_value = 'Active' 
      and activatedEvent.time_stamp > pausedEvent.time_stamp 
      and activatedEvent.[user] = pausedEvent.[user] 
     ORDER BY time_stamp 
    ) activatedEvent 
WHERE 
    pausedEvent.issue_event = 'state changed' 
    and pausedEvent.original_value = 'Active' 
    and pausedEvent.new_value = 'Paused' 

DROP TABLE #Table 

注さまざまなオプションの性能は用意されていたインデックス(私はこれは次のようになりどのくらいの速わからない)に応じて変えることができます。

関連する問題