web-dev-qa-db-ja.com

オーバーナイトセッションを含む、従業員あたりの1日あたりの総労働時間

私はこのようなテーブルを持っています:

CREATE TABLE Table1
(ID int, empid int, time datetime, state int);

+--------------+---------------------+-----------------+
|    empid     |       time          |      state      | 
+--------------+---------------------+-----------------+
(      4       | 2014-03-01 11:12:00 |         0       )  
(      5       | 2014-03-01 12:28:06 |         0       )
(      4       | 2014-03-01 12:50:07 |         1       )
(      4       | 2014-03-01 13:38:00 |         0       )
(      5       | 2014-03-01 13:28:06 |         1       )
(      4       | 2014-03-01 18:42:15 |         1       )
(      4       | 2014-03-02 08:11:08 |         0       ) 
(      4       | 2014-03-02 13:26:11 |         1       ) 
(      5       | 2014-03-02 14:16:15 |         0       ) 
(      4       | 2014-03-02 16:16:15 |         0       ) 
(      5       | 2014-03-02 17:48:21 |         1       ) 
(      4       | 2014-03-02 19:39:03 |         1       ) 
(      5       | 2014-03-02 20:16:15 |         0       )
(      5       | 2014-03-03 04:16:15 |         1       )
+--------------+---------------------+-----------------+

簡潔にするために省略された主キー-参照してください http://www.sqlfiddle.com/#!9/30503/1

0はログインを意味し、1はログアウトを意味します。たとえば、従業員が夜通し働いている場合、1人のユーザーが1日または特定の期間に複数のログイン/ログアウトを行う可能性があります(従業員5が2014-03-02と2014-03-03の間で行うように)

従業員1人あたり1日1シフトあたりの総労働時間を取得しようとしています(たとえば、シフトによっては2日間に及ぶ場合があります)。

1      2014-03-02   total hours worked    08:32:00

私はこのクエリを思いつきました:

SELECT CONCAT(
MOD(TIMEDIFF(MAX(CASE WHEN state = '1' THEN time END),
MIN(CASE WHEN state =    '0' THEN time END)), 24 ), ' hours ',
MINUTE(TIMEDIFF(MAX(CASE WHEN state = '1' THEN time END),
MIN(CASE WHEN state    = '0' THEN time END))), ' minutes') as HoursWorked, 
empid, 
Date(time)
FROM emplog T
GROUP BY empid, Date(time)

これは、最小ログインと最大ログアウトの間の経過時間を私に与えただけです。

以前から 質問 夜勤を含まない、従業員1人あたりの1日の総労働時間を取得する方法を学びました。

select empid, work_dt,
    SEC_TO_TIME(sum(TIMESTAMPDIFF(SECOND,login,logout))) as time_worked
from (
select empid, date(time) as work_dt, time as login
    , coalesce(
          (select min(time) 
           from emplog as b 
           where a.empid = b.empid 
             and date(a.time) = date(b.time)
             and b.time >= a.time 
             and b.state = 1
          ), now()) as logout
from emplog as a 
where a.state = 0
) as t
group by empid, work_dt;

まだ夜勤を考慮に入れる方法を見つけていません-あなたの入力を楽しみにしています。

週末は従業員が働いています。休日は問題になりません。夏時間もそうではありません。

アプリケーションには、同期していないクロックパンチを防止するためのチェックがありませんか?たとえば、出勤/退勤レコードが時系列外であるか、従業員のエラーのために重複しています。デバイスと接続して生データを取得するために記述したコードで、すでにこのような種類の問題に対処しました。コード内のすべての計算を処理する方がよいでしょう。

夜勤は、シフトが始まった日を100%カウントします。たとえば、深夜0時の前に02.01で作業を開始すると、02.01を日付として合計作業時間が保存されます。午前0時以降に開始した場合、総労働時間は日付として03.01で保存されます。

一致するログアウトがない場合は、MySQLデータベースの生データを準備するコードで、事前定義された時間数でユーザーを手動でログアウトします。

3
vibration

パフォーマンスが十分かどうかを確認してください:

SELECT empid
      ,SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND, time, (SELECT IFNULL(MIN(time),NOW())
                                                      FROM emplog b
                                                     WHERE b.empid = a.empid
                                                       AND b.time  > a.time
                                                       AND b.state = 1
                                                    )))) date_worked
  FROM emplog a
 WHERE state=0
 GROUP BY empid;

編集

1日ごとに集計するには:

SELECT empid
      ,DATE(time) day
      ,SEC_TO_TIME(SUM(TIMESTAMPDIFF(SECOND, time, (SELECT IFNULL(MIN(time),NOW())
                                                      FROM emplog b
                                                     WHERE b.empid = a.empid
                                                       AND b.time  > a.time
                                                       AND b.state = 1
                                                    )))) date_worked
  FROM emplog a
 WHERE state=0
 GROUP BY empid, DATE(time);
4
Olli