-- ============================================================================= -- 病区出院随访统计 · 纯查询版(会话变量传参,适合 Navicat/DataGrip 临时取数) -- ============================================================================= -- @start_time / @end_time 就是原来写死的 endtime 起止,改这两行即可。 -- 注意:这不是视图,变量属于当前连接,换连接要重新 SET。 -- ============================================================================= SET @start_time = '2026-10-04'; -- 出院时间起(含) SET @end_time = '2026-11-03'; -- 出院时间止(含当天) SET @followUpCountStyle = '1'; -- 1=应随访 3=仅成功 其它=全部 SET @timelyDays = 7; -- 及时天数基数 SELECT t.leavehospitaldistrictname, -- 出院病区 t.deptname, -- 出院科室 t.dischargeCount, -- 出院人次(首次随访记录数) t.nonFollowUp, -- 无需随访人次 t.followUpNeeded, -- 应随访人次 t.needFollowUp, -- 首次应随访(= 应随访人次) t.pendingFollowUp, -- 首次待随访 t.followUpSuccess, -- 首次随访成功 t.followUpFail, -- 首次随访失败(含人工超时) t.manualSuccess, -- 首次人工随访成功 t.voiceSuccess, -- 首次语音随访成功 t.smsSuccess, -- 首次短信随访成功 t.weChatSuccess, -- 首次微信随访成功 -- 随访成功率 = 成功 / 应随访(只算成功,不含失败) IF(t.needFollowUp = 0, '0.00%', CONCAT(ROUND(100 * t.followUpSuccess / t.needFollowUp, 2), '%')) AS followUpSuccessRate, -- 渠道合计成功率 = 四种方式成功之和 / 四种方式命中之和 IF(t.manual + t.voice + t.sms + t.weChat = 0, '0.00%', CONCAT(ROUND(100 * (t.manualSuccess + t.voiceSuccess + t.smsSuccess + t.weChatSuccess) / (t.manual + t.voice + t.sms + t.weChat), 2), '%')) AS channelSuccessRate, -- 及时率:及时 = finishtime 不为空 且 DATEDIFF(finishtime, endtime) <= 及时天数 + 补偿天数 IF(IFNULL(rt.timely_base, 0) = 0, '0.00%', CONCAT(ROUND(100 * rt.timely_cnt / rt.timely_base, 2), '%')) AS timelyRate FROM ( SELECT r.ward_code AS ward_code, MAX(r.ward_name) AS leavehospitaldistrictname, MAX(r.dept_name) AS deptname, COUNT(*) AS dischargeCount, SUM(r.f_no) AS nonFollowUp, SUM(r.f_need) AS followUpNeeded, SUM(r.f_need) AS needFollowUp, SUM(IF(r.sendstate = 2, 1, 0)) AS pendingFollowUp, SUM(r.f_succ) AS followUpSuccess, SUM(r.f_fail) AS followUpFail, SUM(IF(r.ch_hit = 1 AND r.cp = '1', 1, 0)) AS manual, SUM(IF(r.ch_hit = 1 AND r.cp = '3', 1, 0)) AS voice, SUM(IF(r.ch_hit = 1 AND r.cp = '4', 1, 0)) AS sms, SUM(IF(r.ch_hit = 1 AND r.cp = '5', 1, 0)) AS weChat, SUM(IF(r.sendstate = 6 AND r.cp = '1', 1, 0)) AS manualSuccess, SUM(IF(r.sendstate = 6 AND r.cp = '3', 1, 0)) AS voiceSuccess, SUM(IF(r.sendstate = 6 AND r.cp = '4', 1, 0)) AS smsSuccess, SUM(IF(r.sendstate = 6 AND r.cp = '5', 1, 0)) AS weChatSuccess FROM ( SELECT ss.leavehospitaldistrictcode AS ward_code, ss.leavehospitaldistrictname AS ward_name, ss.leaveldeptname AS dept_name, ss.sendstate AS sendstate, ss.current_preachform AS cp, IF(ss.sendstate = 4, 1, 0) AS f_no, IF(ss.sendstate IS NOT NULL AND ss.sendstate <> 4, 1, 0) AS f_need, IF(ss.sendstate = 6, 1, 0) AS f_succ, IF(ss.sendstate IN (5, 7), 1, 0) AS f_fail, -- 随访方式命中条件:方式 1 排除「无需随访」;方式 3 只算已完成;其它方式不设限 IF(@followUpCountStyle = '1', IF(ss.sendstate IS NOT NULL AND ss.sendstate <> 4, 1, 0), IF(@followUpCountStyle = '3', IF(ss.sendstate = 6, 1, 0), IF(ss.sendstate IS NOT NULL, 1, 0))) AS ch_hit FROM service_subtask ss WHERE ss.del_flag = 0 AND ss.service_type = '2' AND ss.visit_count = 1 -- 只要首次随访 AND ss.leavehospitaldistrictcode IS NOT NULL AND ss.endtime >= DATE(@start_time) AND ss.endtime < DATE_ADD(DATE(@end_time), INTERVAL 1 DAY) AND ss.orgid = '20001001' ) r GROUP BY r.ward_code ) t LEFT JOIN ( -- 及时率:按病区预聚合一次再关联,避免一对多放大分母 SELECT ss.leavehospitaldistrictcode AS ward_code, COUNT(*) AS timely_base, SUM(IF(ss.finishtime IS NOT NULL AND DATEDIFF(ss.finishtime, ss.endtime) <= @timelyDays + IFNULL(cp.compensate_days, 0), 1, 0)) AS timely_cnt FROM service_subtask ss LEFT JOIN ( -- 补偿时间:varchar 且可能是空串,先按子任务聚合成一行 SELECT subid, SUM(CAST(COALESCE(NULLIF(TRIM(compensate_time), ''), '0') AS SIGNED)) AS compensate_days FROM service_subtask_preachform WHERE del_flag = 0 GROUP BY subid ) cp ON cp.subid = ss.id WHERE ss.del_flag = 0 AND ss.service_type = '2' AND ss.visit_count = 1 AND ss.leavehospitaldistrictcode IS NOT NULL AND ss.visit_time IS NOT NULL AND ss.sendstate <> 4 AND DATE(ss.visit_time) < DATE(NOW()) -- 接口未传 startTime/endTime 时的固定条件 AND ss.endtime >= DATE(@start_time) AND ss.endtime < DATE_ADD(DATE(@end_time), INTERVAL 1 DAY) AND ss.orgid = '20001001' GROUP BY ss.leavehospitaldistrictcode ) rt ON rt.ward_code = t.ward_code ORDER BY t.dischargeCount DESC;