2017-10-26 56 views
1

以下の私の問題を助けてください。私は、ユーザーがセキュリティシステムにログインしているかどうかを示すSQL Serverデータベース内のデータを持っています。SQL Server:重複する行を避けるためのウィンドウ関数

データの構造は、次のとおりです。

id SystemId Time   PC User Logged 
----------------------------------------------- 
1 2  20171025 16:01 1 John In 
2 2  20171025 17:41 4 Mike In 
3 2  20171025 17:58 1 John Out 
4 2  20171025 17:58 4 Mike Out 
5 2  20171025 19:21 4 Peter In 
6 2  20171025 21:45 4 Peter In 
7 2  20171025 22:59 4 Peter Out 

私は30分ごとに実行され、セキュリティ監視システムにログインユーザがいないときに表示しなければならないスクリプトを開発する必要があります。

以下のスクリプトは、システム/ネットワークに問題があり、ユーザーを強制的にログアウトしてから強制的にログオフしないでデータベースに記録するという例外を除いてジョブを実行します。つまり、ログアウトしたユーザーは行6に記録されず、代わりにログインしたユーザーのみでした。

これは、23時30分にスクリプトを実行して、Peter(この例では)がログインして仕事をしているかどうかを調べると、実際に彼がログインしていなかった't。 (行6を参照)

私の解決策は、列(PC、User、Logged)に同じ値を持つ連続する行をスキップするウィンドウ関数(パーティション単位)だと思います。このように私は二重計算を避けるでしょう。しかし、私は正しい方向にいるのかどうかはわかりません。

SELECT 
    SystemId, 
    SUM(CASE 
      WHEN Logged = 'In' THEN 1 
      WHEN Logged = 'Out' THEN -1 
      ELSE 0 
     END) AS Connected 
FROM 
    log.SecurityLogs 
GROUP BY 
    SystemId 
HAVING 
    SUM(CASE 
      WHEN Logged = 'In' THEN 1 
      WHEN Logged = 'Out' THEN -1 
      ELSE 0 
     END) = 0 

答えて

1

InOut間のユーザの状態が変化します。あなたが書いたものから、ネストされた状態はありません(つまり、In> In> Out> Out)。だから、

、ちょうど最大時間を比較:

select sl.SystemId, 
     max(case when logged = 'In' then time end) as in_time, 
     max(case when logged = 'Out' then time end) as out_time 
from log.SecurityLogs sl 
group by sl.SystemId; 

あなたはその最新のイベントそして、「中」だったものが必要な場合:

select sl.SystemId, 
     max(case when logged = 'In' then time end) as in_time, 
     max(case when logged = 'Out' then time end) as out_time 
from log.SecurityLogs sl 
group by sl.SystemId 
having max(case when logged = 'In' then time end) > max(case when logged = 'Out' then time end); 
+0

おかげMr.Linoff、もう一度あなたが保存されているが私。あなたの助けと時間のために非常に感謝します。あなたの提案は期待どおりに機能しました。 – ct14

関連する問題