SQL分组关联查询中如何获取日期范围内的TotalHRs数据
问题分析与解决方案
你遇到的核心问题是子查询没有先过滤指定日期范围就进行分组统计,导致两个关键问题:
- 外层
WHERE条件会过滤掉那些在目标日期范围外也有考勤记录的员工(因为他们的min_date早于2019-01-01,或max_date晚于2019-01-30); - 即使员工在目标范围内有记录,
TotalHRsS的计算也是基于所有历史考勤数据,而非仅目标范围的时长。
另外你原SQL中计算TotalHRsS的部分存在括号不匹配的语法错误,我也一并修正了。
以下是修正后的SQL语句:
SELECT B.emp_reader_id, B.emp_name AS Name, Ds.desn_name AS Desn_Name, -- 处理无考勤记录的情况,显示00:00:00 ISNULL( RIGHT('0' + CONVERT(VARCHAR(2), SUM(DATEDIFF(ms, '00:00:00.000', s.TotalHrs)) / 3600000), 2) + ':' + RIGHT('0' + CONVERT(VARCHAR(2), (SUM(DATEDIFF(ms, '00:00:00.000', s.TotalHrs)) / 60000) % 60), 2) + ':' + RIGHT('0' + CONVERT(VARCHAR(2), (SUM(DATEDIFF(ms, '00:00:00.000', s.TotalHrs)) / 1000) % 60), 2), '00:00:00' ) AS TotalHRsS, -- 无考勤时显示指定范围的起始和结束日期 ISNULL(MIN(s.att_date), '2019-01-01') AS min_date, ISNULL(MAX(s.att_date), '2019-01-30') AS max_date FROM employee B LEFT JOIN Daily_attendance_data s ON B.emp_reader_id = s.emp_reader_id -- 关键:先在JOIN条件里过滤目标日期范围的考勤记录 AND s.att_date BETWEEN '2019-01-01' AND '2019-01-30' LEFT JOIN designation Ds ON B.desn_id = Ds.DESN_ID -- 原SQL中departments表未用到字段,可根据实际需求添加 GROUP BY B.emp_reader_id, B.emp_name, Ds.desn_name
关键修改点说明:
- 日期过滤时机调整:把日期范围过滤从外层
WHERE移到Daily_attendance_data的JOIN条件中,既能只统计目标范围内的考勤时长,又能保留所有员工(无考勤的员工会返回NULL,后续用ISNULL处理)。 - TotalHRsS计算修正:修复了原语句的括号错误,同时调整毫秒转时分秒的计算逻辑(毫秒转小时需除以3600000,分钟是除以60000后取余,秒是除以1000后取余)。
- 无考勤场景处理:用
ISNULL函数处理无考勤的情况,让TotalHRsS显示00:00:00,min_date和max_date显示你指定的范围边界,完全匹配你的期望输出。 - 逻辑简化:去掉了无用的子查询和重复的
employee表JOIN,让SQL更简洁高效。
内容的提问来源于stack exchange,提问作者Dolu bolu
相关产品推荐
相关产品推荐

