求MySQL/SQL Server查询语句:按日期展示员工上下班考勤记录
考勤记录查询需求与实现语句
原始考勤表结构与数据
| Card_ID | Date_Entry | Status_Entry |
|---|---|---|
| 5001201 | 2024-01-01 07:50:05 | IN |
| 5001201 | 2024-01-01 17:00:07 | OUT |
| 5001202 | 2024-01-01 07:56:00 | IN |
| 5001202 | 2024-01-01 17:01:15 | OUT |
| 5001203 | 2024-01-01 07:58:20 | IN |
| 5001204 | 2024-01-01 08:00:15 | IN |
| 5001204 | 2024-01-01 17:02:00 | OUT |
| 5001201 | 2024-01-02 07:55:05 | IN |
| 5001201 | 2024-01-02 17:02:07 | OUT |
| 5001202 | 2024-01-02 07:50:00 | IN |
| 5001202 | 2024-01-02 17:00:10 | OUT |
| 5001203 | 2024-01-02 07:59:20 | IN |
| 5001203 | 2024-01-02 08:03:15 | OUT |
| 5001204 | 2024-01-02 17:03:15 | OUT |
查询需求
需要查询指定日期范围(示例:2024-01-01 至 2024-01-03)内的考勤记录,要求:
- 展示日期范围内的所有日期
- 每个员工每日的
Clock_In(上班时间)和Clock_Out(下班时间) - 无对应记录时显示
NULL
期望输出格式
| Date_Log | Card_ID | Clock_In | Clock_Out |
|---|---|---|---|
| 2024-01-01 | 5001201 | 2024-01-01 07:50:05 | 2024-01-01 17:00:07 |
| 2024-01-01 | 5001202 | 2024-01-01 07:56:00 | 2024-01-01 17:01:15 |
| 2024-01-01 | 5001203 | 2024-01-01 07:58:20 | NULL |
| 2024-01-01 | 5001204 | 2024-01-01 08:00:15 | 2024-01-01 17:02:00 |
| 2024-01-02 | 5001201 | 2024-01-02 07:55:05 | 2024-01-02 17:02:07 |
| 2024-01-02 | 5001202 | 2024-01-02 07:50:00 | 2024-01-02 17:00:10 |
| 2024-01-02 | 5001203 | 2024-01-02 07:59:20 | 2024-01-02 08:03:15 |
| 2024-01-02 | 5001204 | NULL | 2024-01-02 17:03:15 |
| 2024-01-03 | 5001201 | NULL | NULL |
| 2024-01-03 | 5001202 | NULL | NULL |
| 2024-01-03 | 5001203 | NULL | NULL |
| 2024-01-03 | 5001204 | NULL | NULL |
实现语句
MySQL 查询语句
-- 生成日期范围表(递归方式支持任意长度的日期区间) WITH RECURSIVE date_range AS ( SELECT '2024-01-01' AS Date_Log UNION ALL SELECT DATE_ADD(Date_Log, INTERVAL 1 DAY) FROM date_range WHERE Date_Log < '2024-01-03' ), -- 获取所有员工ID employee_list AS ( SELECT DISTINCT Card_ID FROM attendance_table ) -- 交叉连接生成所有日期-员工组合,左连接考勤数据并聚合 SELECT dr.Date_Log, el.Card_ID, MAX(CASE WHEN at.Status_Entry = 'IN' THEN at.Date_Entry END) AS Clock_In, MAX(CASE WHEN at.Status_Entry = 'OUT' THEN at.Date_Entry END) AS Clock_Out FROM date_range dr CROSS JOIN employee_list el LEFT JOIN attendance_table at ON el.Card_ID = at.Card_ID AND DATE(at.Date_Entry) = dr.Date_Log GROUP BY dr.Date_Log, el.Card_ID ORDER BY dr.Date_Log, el.Card_ID;
SQL Server 查询语句
-- 生成日期范围表(递归方式支持任意长度的日期区间) WITH date_range AS ( SELECT CAST('2024-01-01' AS DATE) AS Date_Log UNION ALL SELECT DATEADD(DAY, 1, Date_Log) FROM date_range WHERE Date_Log < '2024-01-03' ), -- 获取所有员工ID employee_list AS ( SELECT DISTINCT Card_ID FROM attendance_table ) -- 交叉连接生成所有日期-员工组合,左连接考勤数据并聚合 SELECT dr.Date_Log, el.Card_ID, MAX(CASE WHEN at.Status_Entry = 'IN' THEN at.Date_Entry END) AS Clock_In, MAX(CASE WHEN at.Status_Entry = 'OUT' THEN at.Date_Entry END) AS Clock_Out FROM date_range dr CROSS JOIN employee_list el LEFT JOIN attendance_table at ON el.Card_ID = at.Card_ID AND CAST(at.Date_Entry AS DATE) = dr.Date_Log GROUP BY dr.Date_Log, el.Card_ID ORDER BY dr.Date_Log, el.Card_ID;
注意事项
- 替换语句中的
attendance_table为实际的考勤表名称 - 若仅需短日期范围,也可替换递归CTE为手动枚举的方式(如使用
UNION ALL或VALUES生成日期序列)
内容的提问来源于stack exchange,提问作者Pramono
相关产品推荐
相关产品推荐

