SQL JOIN 一對多關係,僅關聯最早、最後一筆日期時間記錄
現有資料表
假設現有 employees (員工) 和 clocks (打卡出勤記錄) 兩張 table 資料。
| id | namt | 
|---|---|
| E201308002 | 李四 | 
| E202003001 | 小美 | 
| id | in_time | out_time | employees_id (FK) | 
|---|---|---|---|
| 1 | 2020-08-25 07:52:00 | 2020-08-25 17:37:00 | E201308002 | 
| 2 | 2020-08-26 07:50:00 | 2020-08-26 17:08:00 | E201308002 | 
| 3 | 2020-08-26 07:53:00 | 2020-08-26 17:24:00 | E202003001 | 
| 4 | 2020-08-27 07:54:00 | 2020-08-27 17:10:00 | E202003001 | 
| 5 | 2020-08-30 07:41:00 | 2020-08-30 17:40:00 | E202003001 | 
僅關聯最早、最後一筆日期時間記錄
employees 和 clocks 是一對多 (one-to-many) 的關係,使用 JOIN 的查詢結果則會以 clocks 的資料數量取得對應的 rows。
SELECT
    employees.id AS employees_id,
    employees.name AS employees_name,
    clocks.id AS clocks_id,
    DATE_FORMAT(clocks.in_time, '%Y-%m-%d %H:%i') AS clocks_in_time,
    DATE_FORMAT(clocks.out_time, '%Y-%m-%d %H:%i') AS clocks_out_time
FROM employees
    LEFT JOIN clocks
        ON employees.id = clocks.employees_id| employees_id | employees_name | clocks_id | clocks_in_time | clocks_out_time | 
|---|---|---|---|---|
| E201308002 | 李四 | 1 | 2020-08-25 07:52 | 2020-08-25 17:37 | 
| E201308002 | 李四 | 2 | 2020-08-26 07:50 | 2020-08-26 17:08 | 
| E202003001 | 小美 | 3 | 2020-08-26 07:53 | 2020-08-26 17:24 | 
| E202003001 | 小美 | 4 | 2020-08-27 07:54 | 2020-08-27 17:10 | 
| E202003001 | 小美 | 5 | 2020-08-30 07:41 | 2020-08-30 17:40 | 
JOIN 透過子查詢 (subquery) 來完成:
- 僅關聯 in_time 最早一筆日期時間記錄。
- 僅關聯 out_time 最後一筆日期時間記錄。
SELECT
    employees.id AS employees_id,
    employees.name AS employees_name,
    DATE_FORMAT(clocks_first.in_time, '%Y-%m-%d %H:%i') AS clocks_first_in_time,
    DATE_FORMAT(clocks_last.out_time, '%Y-%m-%d %H:%i') AS clocks_last_out_time
FROM employees
    -- 子查詢,僅關聯 in_time 最早一筆日期時間記錄
    LEFT JOIN (
        SELECT
            c1.in_time,
            c1.employees_id
        FROM employees
            JOIN clocks AS c1
                ON (employees.id = c1.employees_id)
            LEFT OUTER JOIN clocks AS c2
                ON (
                    employees.id = c2.employees_id
                    AND (
                        c1.in_time > c2.in_time
                        OR c1.in_time = c2.in_time
                        AND c1.id > c2.id
                    )
                )
        WHERE c2.id IS NULL
    ) AS clocks_first
        ON clocks_first.employees_id = employees.id
    -- 子查詢,僅關聯 out_time 最後一筆日期時間記錄
    LEFT JOIN (
        SELECT
            c1.out_time,
            c1.employees_id
        FROM employees
            JOIN clocks AS c1
                ON (employees.id = c1.employees_id)
            LEFT OUTER JOIN clocks AS c2
                ON (
                    employees.id = c2.employees_id
                    AND (
                        c1.out_time < c2.out_time
                        OR c1.out_time = c2.out_time
                        AND c1.id < c2.id
                    )
                )
        WHERE c2.id IS NULL
    ) AS clocks_last
        ON clocks_last.employees_id = employees.id| employees_id | employees_name | clocks_first_in_time | clocks_last_out_time | 
|---|---|---|---|
| E201308002 | 李四 | 2020-08-25 07:52 | 2020-08-26 17:08 | 
| E202003001 | 小美 | 2020-08-26 07:53 | 2020-08-30 17:40 | 
參考
 
                            本著作係採用創用 CC 姓名標示-相同方式分享 3.0 台灣 授權條款授權.
 
                    