/* PostgreSQL */ /* 用 CTE 把 query 一個一個串起來、比較好閱讀 */ WITH /* 先把每一筆紀錄的前後紀錄找出來,放在同一筆 row */ working_records AS ( SELECT emp_no, LAG(flag, 1) OVER (PARTITIONBY emp_no ORDERBY log_time ASC) AS prev_record_flag, LAG(log_time, 1) OVER (PARTITIONBY emp_no ORDERBY log_time ASC) AS prev_record_time, flag AS current_flag, log_time AS current_record_time, LEAD(flag, 1) OVER (PARTITIONBY emp_no ORDERBY log_time ASC) AS next_record_flag, LEAD(log_time, 1) OVER (PARTITIONBY emp_no ORDERBY log_time ASC) AS next_record_time FROM test_anson_employee_working_records ),
/* 套用剛剛提到的規則篩選出要留下的紀錄 */ filtered_working_records AS ( SELECT emp_no, current_flag, current_record_time FROM working_records WHERE (current_flag ='CHECK_IN'AND prev_record_flag isnull) or (current_flag ='CHECK_IN'AND prev_record_flag ='CHECK_OUT') or (current_flag ='CHECK_OUT'AND next_record_flag ='CHECK_IN') or (current_flag ='CHECK_OUT'AND next_record_flag isnull) ),
working_hours AS ( /* 找出每一筆上班紀錄,然後再用一次 `LEAD` 找出下一筆下班紀錄(因為已經篩選過,所以資料都是上下班按照順序排序)算出當次的上班時間 */ /* 待修正:沒辦法正確算出 diff ,可能是 PARTITION 的問題? */ SELECT emp_no, LEAD(current_record_time, 1) OVER (PARTITIONBY emp_no ORDERBY current_record_time) - current_record_time FROM filtered_working_records WHERE current_flag ='CHECK_IN' )