SQL查询如何合并同员工同楼层同日期下的多个班次数据
SQL实现方案
核心逻辑:按StaffID、Name、Floor、Date四个维度分组,对同组内的Shift字段做字符串拼接即可。因为Floor已经加入分组维度,同一员工同一天跨楼层的班次会自动拆分为独立行,完全匹配你的业务要求。
1. SQL Server 2017+ / Azure SQL 版本(推荐)
直接使用内置STRING_AGG聚合函数实现,语法简洁性能最优:
SELECT ST.STAFFNUM [StaffID], ST.FULLNAME [Name], ST.AREA [Floor], CONVERT(VARCHAR(10), TS.EVENTDATE, 103) [Date], STRING_AGG( CONCAT(LEFT(CONVERT(VARCHAR(10), TS.SHIFTSTART, 8), 5),'-',LEFT(CONVERT(VARCHAR(10), TS.SHIFTEND, 8), 5)), ', ' ) WITHIN GROUP (ORDER BY TS.SHIFTSTART) [Shifts] FROM TIMES TS LEFT JOIN STAFF ST ON TS.STAFFNUM = ST.STAFFNUM WHERE TS.EVENTDATE BETWEEN '2021/01/01' AND '2021/01/01' GROUP BY ST.STAFFNUM, ST.FULLNAME, ST.AREA, CONVERT(VARCHAR(10), TS.EVENTDATE, 103) ORDER BY ST.AREA, ST.FULLNAME, [Date] ;
这里的WITHIN GROUP (ORDER BY TS.SHIFTSTART)可以保证拼接的班次按开始时间正序排列,符合日常使用习惯。
2. SQL Server 2016及更低版本
旧版本没有STRING_AGG,可以用FOR XML PATH写法实现拼接:
WITH ShiftBase AS ( -- 先拼接好单条班次的格式 SELECT ST.STAFFNUM [StaffID], ST.FULLNAME [Name], ST.AREA [Floor], CONVERT(VARCHAR(10), TS.EVENTDATE, 103) [Date], CONCAT(LEFT(CONVERT(VARCHAR(10), TS.SHIFTSTART, 8), 5),'-',LEFT(CONVERT(VARCHAR(10), TS.SHIFTEND, 8), 5)) [Shift], TS.SHIFTSTART FROM TIMES TS LEFT JOIN STAFF ST ON TS.STAFFNUM = ST.STAFFNUM WHERE TS.EVENTDATE BETWEEN '2021/01/01' AND '2021/01/01' ) SELECT DISTINCT StaffID, Name, Floor, [Date], STUFF(( SELECT ', ' + Shift FROM ShiftBase t2 WHERE t2.StaffID = t1.StaffID AND t2.Name = t1.Name AND t2.Floor = t1.Floor AND t2.[Date] = t1.[Date] ORDER BY t2.SHIFTSTART FOR XML PATH(''), TYPE ).value('.', 'VARCHAR(MAX)'), 1, 2, '') [Shifts] FROM ShiftBase t1 ORDER BY Floor, Name, [Date] ;
3. 其他数据库适配
- MySQL:将上面的
STRING_AGG替换为GROUP_CONCAT即可:GROUP_CONCAT( CONCAT(LEFT(TS.SHIFTSTART, 5),'-',LEFT(TS.SHIFTEND, 5)) ORDER BY TS.SHIFTSTART SEPARATOR ', ' ) AS Shifts - PostgreSQL:和SQL Server 2017+语法一致,直接用
STRING_AGG函数即可。
内容的提问来源于stack exchange,提问作者S.Hampton
相关产品推荐
相关产品推荐

