チェックインとチェックアウトのリストからタイムスパンを計算するにはどうすればよいですか?
-
07-07-2019 - |
質問
自分のプロジェクトを管理するための簡単な時間追跡プログラムを書いています。私はデータベースにコードをレポートし続けるのが大好きなので、請求書やタイムシートなどを生成するいくつかのsprocを作成しようとしています。
クロックアクション、IE「パンチイン」、「パンチアウト」を含むテーブルがあります。また、このアクションを実行したユーザー、アクションに関連付けられたプロジェクト、および現在の日付/時刻も含まれています。
このテーブルから選択して特定の時間/プロジェクト/およびユーザーのクロックインを取得できますが、各クロックインおよびアウトが2行から合計時間を含む単一の行に変換されるように集約します。
たとえば、出力例は次のとおりです。
ClockActionID ActionType DateTime
-------------------- ---------- -----------------------
17 1 2008-11-08 18:33:56.000
18 2 2008-11-08 18:33:59.587
19 1 2008-11-08 18:34:01.023
20 2 2008-11-08 18:34:02.037
21 1 2008-11-08 18:45:06.317
22 2 2008-11-08 18:46:14.597
23 1 2008-11-08 18:46:16.283
24 2 2008-11-08 18:46:17.173
25 1 2008-11-08 18:50:37.830
26 2 2008-11-08 18:50:39.737
27 1 2008-11-08 18:50:40.547
(11 row(s) affected)
ActionType 1が" ClockIn"の場合ActionType 2は「ClockOut」です。また、簡潔にするために、ユーザー、プロジェクト、および説明の列も削除しました。
純粋なSQLで、次のような結果セットを生成する必要があります。
Description | Total Time
各ClockIn / ClockOutペアごと。
これは実際にはかなり単純になると思いますが、どちらにアプローチするのかよくわかりません。
編集:ユーザーは複数のプロジェクトに同時に時間を入力できますが、最初に結果セットを単一のプロジェクトに絞り込むことにより、ここでのロジックに違いはありません。
解決
デザインは最高のものではないことに同意します。開始から終了までの行が1つしかないイベントベースの構造は、おそらく多くの時間を節約できます。その場合、誰かが出勤するときに終了日がnullのレコードを作成できます。次に、出勤するときに終了日を入力します。
しかし、それはあなたが尋ねたことではありません。これが問題の解決策です。
DECLARE @clock TABLE (ClockActionID INT PRIMARY KEY IDENTITY, ActionType INT, ActionDateTime DATETIME)
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:00:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:01:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:02:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:03:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:04:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:05:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:06:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:07:00')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (1,'20080101 00:08:12')
INSERT INTO @clock (ActionType, ActionDateTime) VALUES (2,'20080101 00:09:00')
-- Get the range
SELECT ActionDateTime CheckIn,
(SELECT TOP 1 ActionDateTime
FROM @clock C2
WHERE C2.ActionDateTime > C.ActionDateTime) CheckOut
FROM @clock C
WHERE ActionType = 1
-- Get the duration
SELECT DATEDIFF(second, ActionDateTime,
(SELECT TOP 1 ActionDateTime
FROM @clock C2
WHERE C2.ActionDateTime > C.ActionDateTime)
) / 60.0 Duration_Minutes
FROM @clock C
WHERE ActionType = 1
私は、テストのためだけにMS SQL Serverで動作するテーブル変数を使用していることに注意してください。必要に応じて変更します。また、SQL Server 2000は、このようなクエリではうまく動作しないことにも注意してください。テスト結果は次のとおりです。
CheckIn CheckOut
2008-01-01 00:00:00.000 2008-01-01 00:01:00.000
2008-01-01 00:02:00.000 2008-01-01 00:03:00.000
2008-01-01 00:04:00.000 2008-01-01 00:05:00.000
2008-01-01 00:06:00.000 2008-01-01 00:07:00.000
2008-01-01 00:08:12.000 2008-01-01 00:09:00.000
Duration_Minutes
1.000000
1.000000
1.000000
1.000000
0.800000
他のヒント
元のストレージスキーマに欠陥があると思います。時計の観点から見ているので、ClockActionです。プロジェクトの観点からはどうですか?
TABLE ProjectAction(Projectid、Userid、Type、Start、End)
その後、単純なGROUP BYでトリックを行う必要があります。
次のようなことを考えましたか:
- 誰かが出勤を忘れているので、二回出勤しているように見えますか?
- 誰かが出勤を忘れているので、出勤が2回あるように見えますか?
前者の場合、2番目の出勤を単に無視するのは正しいですか?受け入れられた回答は、両方のクロックインを同じクロックアウトにバインドします。正しいですか?
2番目の場合、2番目の退出は無視されます。正しいですか?