能否通过单条SQL查询获取多维度服务台工单统计数据?
一次性搞定服务台多维度工单统计的SQL优化方案
嘿,你现在在做服务台的指标统计,要拿每个用户的总工单数、超7天和超30天的未结工单数,不用重复跑三次SQL啦!用条件聚合的方式就能一次查询搞定所有数据,效率和可读性都能提升不少。
先给你两种可行的写法,你可以根据自己的习惯选:
方法一:用JOIN关联表直接统计
SELECT u.user_login AS UserName, COUNT(*) AS 总工单数, -- 统计超7天的工单:符合条件记1,否则0,求和就是数量 SUM(CASE WHEN DATEDIFF(day, COALESCE(i.created_on, s.created_on), GETDATE()) > 7 THEN 1 ELSE 0 END) AS 超7天工单数, -- 同理统计超30天的工单 SUM(CASE WHEN DATEDIFF(day, COALESCE(i.created_on, s.created_on), GETDATE()) > 30 THEN 1 ELSE 0 END) AS 超30天工单数 FROM [fpscdb008_system].[asgnmt] a JOIN [fpscdb008_system].[app_user] u ON u.app_user_id = a.app_user_id -- 关联事件工单表,过滤未关闭的记录 LEFT JOIN [fpscdb008_ws_004].[incidents] i ON i.id = a.item_id AND a.item_defn_id = 12610 AND i.soft_delete_id = 0 AND i.status_1 NOT IN ('Closed','Resolved','Cancelled') -- 关联服务请求表,同样过滤未关闭的记录 LEFT JOIN [fpscdb008_ws_004].[service_request] s ON s.id = a.item_id AND a.item_defn_id = 7861 AND s.soft_delete_id = 0 AND s.status_1 NOT IN ('Closed','Resolved','Cancelled') -- 确保只统计有对应工单的分配记录 WHERE i.id IS NOT NULL OR s.id IS NOT NULL GROUP BY u.user_login ORDER BY u.user_login;
方法二:用CTE先合并所有工单再统计
这种方式逻辑更清晰,把所有未关闭的工单先合并成一个数据集,再做统计:
WITH AllOpenTickets AS ( -- 先取所有未关闭的事件工单 SELECT u.user_login AS UserName, i.created_on AS CreatedDate FROM [fpscdb008_system].[asgnmt] a JOIN [fpscdb008_system].[app_user] u ON u.app_user_id = a.app_user_id JOIN [fpscdb008_ws_004].[incidents] i ON i.id = a.item_id AND a.item_defn_id = 12610 WHERE i.soft_delete_id = 0 AND i.status_1 NOT IN ('Closed','Resolved','Cancelled') -- 用UNION ALL保留所有记录,避免UNION自动去重导致数据丢失 UNION ALL -- 再取所有未关闭的服务请求工单 SELECT u.user_login AS UserName, s.created_on AS CreatedDate FROM [fpscdb008_system].[asgnmt] a JOIN [fpscdb008_system].[app_user] u ON u.app_user_id = a.app_user_id JOIN [fpscdb008_ws_004].[service_request] s ON s.id = a.item_id AND a.item_defn_id = 7861 WHERE s.soft_delete_id = 0 AND s.status_1 NOT IN ('Closed','Resolved','Cancelled') ) -- 基于合并后的数据集做多维度统计 SELECT UserName, COUNT(*) AS 总工单数, SUM(CASE WHEN DATEDIFF(day, CreatedDate, GETDATE()) > 7 THEN 1 ELSE 0 END) AS 超7天工单数, SUM(CASE WHEN DATEDIFF(day, CreatedDate, GETDATE()) > 30 THEN 1 ELSE 0 END) AS 超30天工单数 FROM AllOpenTickets GROUP BY UserName ORDER BY UserName;
几个关键点说明:
- 条件聚合:核心就是用
CASE WHEN配合SUM()(或COUNT())来实现分组内的多维度统计,不用重复执行多次查询。 - UNION ALL vs UNION:一定要用
UNION ALL,因为UNION会自动去重,如果有重复的工单记录(比如同一工单多次分配)会被过滤掉,导致统计不准。 - 时间计算:用
DATEDIFF(day, CreatedDate, GETDATE())直接计算工单创建至今的天数差,比CreatedDate <= GETDATE() - 30更直观,逻辑是一致的。
这样你跑一次SQL就能拿到所有需要的指标,不用重复操作,还能减少数据库的查询压力~
内容的提问来源于stack exchange,提问作者Brian Susol
相关产品推荐
相关产品推荐

