MySQL 5.7.12:如何按月份、工单类型、状态计算工单解决率
问题分析
你的核心问题在于GROUP BY中包含了status字段——这导致每个分组只能统计对应状态的工单数量,根本拿不到同一月份、同一工单类型的总工单总数。所以计算解决率时,分母要么是当前状态的工单量(比如已解决分组的分母就是已解决数本身,自然算出100%),要么出现除数为0的NULL情况,完全不符合需求。
解决方案
考虑到你用的是MySQL 5.7(不支持8.0才有的窗口函数),我们可以用预统计总工单数量+关联查询的方式解决:先单独算出每个月份、每个工单类型的总工单总数,再把这个结果和原状态分组的数据关联,最后用已解决数除以总工单数量得到正确的解决率。
修改后的SQL查询
SELECT st.createdAt, st.count, st.typeId, st.status, st.status2, st.notStatus2, -- 按状态计算解决率:已解决状态用已解决数/总工单数,未解决状态直接返回0 CASE WHEN st.status = 2 THEN ROUND((st.status2 / total.total_count) * 100, 4) ELSE 0.0000 END AS pct FROM ( -- 原逻辑:按月份、工单类型、状态分组,统计各状态的工单量 SELECT date_format(t.added,'%Y%m') createdAt, count(t.id) count, t.type_id typeId, tt.name ticketType, t.status, sum(if(t.status=2,1,0)) AS status2, sum(if(t.status!=2,1,0)) AS notStatus2 FROM tickets t JOIN ticket_types tt ON tt.id=t.type_id WHERE t.added BETWEEN '2018-07-01' AND '2019-07-01' GROUP BY createdAt, tt.name, t.status ) AS st -- 关联预统计的总工单表,拿到同月份同类型的总工单数量 JOIN ( -- 预统计:仅按月份、工单类型分组,得到总工单总数 SELECT date_format(t.added,'%Y%m') createdAt, tt.name ticketType, count(t.id) total_count FROM tickets t JOIN ticket_types tt ON tt.id=t.type_id WHERE t.added BETWEEN '2018-07-01' AND '2019-07-01' GROUP BY createdAt, tt.name ) AS total ON st.createdAt = total.createdAt AND st.ticketType = total.ticketType ORDER BY st.createdAt, st.typeId, st.status;
关键细节说明
- 预统计总工单:新增的
total子查询只按createdAt和ticketType分组,精准拿到每个月份、每个类型的总工单总数,这正是计算解决率需要的正确分母。 - 关联匹配:通过
createdAt和ticketType把原状态分组数据和预统计结果关联,确保每个状态分组都能拿到对应的总工单数量。 - 解决率格式化:用
CASE区分状态,已解决状态(status=2)计算百分比,未解决状态直接返回0;用ROUND()保留4位小数,和你期望的结果格式完全匹配。
结果验证
拿你示例里的数据举例:
- 类型62在201807月的总工单是33+4=37,已解决的33个对应的解决率就是
33/37*100≈89.20%,和期望一致。 - 类型20在201807月的总工单是8+1=9,已解决的8个对应的解决率是
8/9*100≈88.80%,也完全符合预期。
内容的提问来源于stack exchange,提问作者HJ_ZP
相关产品推荐
相关产品推荐

