2017-06-27 11 views
1

以下のスキーマから、私のデータベースの従業員の日中/時間を照会したいと思います。出席者:柔軟なスケジュールのtime_inとtime_outを取得する従業員

注:従業員のスケジュールは柔軟性があり、夜間シフトまたは日シフト(従業員#1で見ることができるように)で作業できます。

スキーマ:出席テーブル

| id | employee_id | timedata   | in_out | 
|----|-------------|---------------------|--------| 
| 1 | 1   | 2017-06-08 13:51:02 | IN  | <- night shift (inserted: 2017-06-08) 
| 2 | 1   | 2017-06-09 01:10:04 | OUT | <- actual time_out (inserted: 2017-06-09) 
| 3 | 1   | 2017-06-09 14:11:40 | IN  | 
| 4 | 1   | 2017-06-09 19:41:26 | OUT | 
| 5 | 2   | 2017-06-08 09:25:17 | IN  | 
| 6 | 2   | 2017-06-08 20:44:14 | OUT | 
| 7 | 2   | 2017-06-09 11:35:00 | IN  | 
| 8 | 2   | 2017-06-09 20:36:06 | OUT | 

これは私がこれまで行ってきたクエリです:

SELECT employee_id, 
     DATE(timedata) as attendance_date, 
     MIN(IF(in_out='IN',timedata,NULL)) AS time_in, 
     MAX(IF(in_out='OUT',timedata,NULL)) AS time_out 
FROM attendances 
GROUP BY employee_id,DATE(timedata) 

このクエリでの問題は、私はのTIME_OUTを得ることができないということですナイトシフト取引。

| employee_id | attendance_date | time_in    | time_out   | 
|-------------|-----------------|---------------------|---------------------| 
| 1   | 2017-06-08  | 2017-06-08 13:51:02 | NULL    | 
| 2   | 2017-06-08  | 2017-06-08 11:25:17 | 2017-06-08 20:44:14 | 
| 2   | 2017-06-09  | 2017-06-09 11:35:00 | 2017-06-09 20:36:06 | 
| 1   | 2017-06-09  | 2017-06-09 14:11:40 | 2017-06-09 19:41:26 | 


ここにある私の 所望の出力

| employee_id | attendance_date | time_in    | time_out   | 
|-------------|-----------------|---------------------|---------------------| 
| 1   | 2017-06-08  | 2017-06-08 13:51:02 | 2017-06-09 01:10:04 | 
| 2   | 2017-06-08  | 2017-06-08 09:25:17 | 2017-06-08 20:44:14 | 
| 1   | 2017-06-09  | 2017-06-09 14:11:40 | 2017-06-09 19:41:26 | 
| 2   | 2017-06-09  | 2017-06-09 11:35:00 | 2017-06-09 20:36:06 | 

任意の提案が高く評価されています。これは、出力されます。

答えて

1

この質問は、MySQLがそのままの状態でサポートしていない分析関数を使用しなければ扱いにくいでしょう。ただし、セッション変数を使用してROW_NUMBERをシミュレートできます。ここでの1つのアプローチは、時間の昇順に関するテーブル内の並置によって、INOUTをグループ化することです。次のクエリを考えてみます。

SET @row_number = 0; 
SET @emp_id = NULL; 

SELECT 
    t.employee_id, 
    DATE(MAX(CASE WHEN in_out = 'IN' THEN timedata END)) AS attendance_date, 
    MAX(CASE WHEN in_out = 'IN' THEN timedata END) AS time_in, 
    MAX(CASE WHEN in_out = 'OUT' THEN timedata END) AS time_out 
FROM 
(
    SELECT *, 
     @row_number:=CASE WHEN @emp_id = employee_id THEN @row_number + 1 ELSE 0 END AS rn, 
     TRUNCATE(@row_number/2, 0) AS rn_grp, 
     @emp_id:=employee_id 
    FROM Attendances 
    ORDER BY employee_id, timedata 
) t 
GROUP BY t.employee_id, t.rn_grp; 

これがどのように機能するかを確認するには、私が生成される行数は、次のように見えるあなたの元のテーブルを離れる:

| id | employee_id | timedata   | in_out | rn_grp | 
|----|-------------|---------------------|--------|--------| 
| 1 | 1   | 2017-06-08 13:51:02 | IN  | 0  | 
| 2 | 1   | 2017-06-09 01:10:04 | OUT | 0  | 
| 3 | 1   | 2017-06-09 14:11:40 | IN  | 1  | 
| 4 | 1   | 2017-06-09 19:41:26 | OUT | 1  | 
| 5 | 2   | 2017-06-08 09:25:17 | IN  | 0  | 
| 6 | 2   | 2017-06-08 20:44:14 | OUT | 0  | 
| 7 | 2   | 2017-06-09 11:35:00 | IN  | 1  | 
| 8 | 2   | 2017-06-09 20:36:06 | OUT | 1  | 

それが今、私たちは、グループを得ることは明らかであるべきemployee_idrn_grpの列を使用して、元の質問にピボットクエリアプローチを使用します。

たとえば、従業員データが対応するOUT値のないIN値を持つことができた場合、この方法は機能しないことに注意してください。

出力:ここ

enter image description here

デモ:あなたはTIME_OUTがtime_in後でTIME_OUTでtime_in結合する自己結合を使用することができます

Rextester

1

。次に、time_inでグループ化し、最初のtime_outだけを選択します。

select employee_id, attendance_date, time_in, MIN(time_out) time_out from (
    select A.id id, DATE(A.timedata) attendance_date, A.employee_id employee_id, A.timedata time_in, A.in_out, B.timedata time_out 
    from attendances A 
    left join attendances B 
     on A.employee_id = B.employee_id 
      and A.timedata < B.timedata 
      and B.in_out = 'OUT'  
    where A.in_out = 'IN' 
) AB 
group by employee_id, attendance_date, time_in 
関連する問題