如何在Teradata中按月份统计员工休假时长(排除周末并精准分摊)
按工作日分摊跨月休假时长的解决方案
看起来你需要把员工的总休假时长按所有涉及的工作日平均分摊到对应月份,我来给你一个基于日历表的具体实现方案,刚好能匹配你想要的结果:
核心思路
- 先筛选出员工所有休假记录覆盖的工作日(排除周末/节假日)
- 计算该员工的总休假时长,以及这些休假涉及的总工作日数量
- 把总时长按每个工作日平均分摊,再按月份汇总得到各月的分摊时长
具体SQL实现
假设你的休假记录表叫LeaveRecords,日历表叫Calendar,先确认表结构:
LeaveRecords:EmployeeID(员工ID)、BeginDate(休假开始日)、EndDate(休假结束日)、TotalHours(该段休假总时长)Calendar:Date(日期)、IsWorkday(是否工作日,1=是,0=否)、YearMonth(年月,格式如'2017-10')
分步查询实现
-- 第一步:找出该员工所有休假涉及的工作日 WITH AllLeaveWorkdays AS ( SELECT lr.EmployeeID, c.Date, c.YearMonth FROM LeaveRecords lr JOIN Calendar c ON c.Date BETWEEN lr.BeginDate AND lr.EndDate WHERE c.IsWorkday = 1 -- 只保留工作日 AND lr.EmployeeID = 168835 -- 可根据需要移除,支持批量员工 ), -- 第二步:计算总休假时长和总工作日数 TotalStats AS ( SELECT EmployeeID, SUM(lr.TotalHours) AS TotalLeaveHours, COUNT(DISTINCT alwd.Date) AS TotalWorkdays FROM LeaveRecords lr JOIN AllLeaveWorkdays alwd ON lr.EmployeeID = alwd.EmployeeID GROUP BY EmployeeID ) -- 第三步:按月份汇总分摊后的时长 SELECT alwd.EmployeeID, alwd.YearMonth, ROUND(SUM(ts.TotalLeaveHours / ts.TotalWorkdays), 2) AS AllocatedHours FROM AllLeaveWorkdays alwd JOIN TotalStats ts ON alwd.EmployeeID = ts.EmployeeID GROUP BY alwd.EmployeeID, alwd.YearMonth ORDER BY alwd.EmployeeID, alwd.YearMonth;
结果验证
针对你的示例数据:
- 总休假时长:32+6=38小时
- 总工作日数:9天(10月31日1天 + 11月的8天)
- 每个工作日分摊时长:38/9≈4.22小时
- 10月分摊:1×4.22=4.22小时
- 11月分摊:8×4.22≈33.76,四舍五入后为33.77小时,和你的预期完全匹配
注意事项
- 确保日历表的
IsWorkday字段准确标记了所有非工作日(包括周末和公司自定义节假日) - 如果需要批量处理所有员工,只需移除
AllLeaveWorkdays中的AND lr.EmployeeID = 168835条件 - 可以通过调整
ROUND函数的第二个参数来控制小数位数,比如保留两位就用ROUND(..., 2)
内容的提问来源于stack exchange,提问作者Gurpreet Singh
相关产品推荐
相关产品推荐

