-- ============================================================================ -- 把 pat_med_inhosp 的「科室 / 病区」回填到 service_subtask(在院 4 列 + 离院 4 列) -- 生成日期:2026-11-06(v2:修正 join 键 + 合并离院维度) -- 适用:MySQL 8.0 / 5.7(未用 CTE、窗口函数) -- -- ⚠️ 前置条件:先执行过 sql/rename_service_subtask_dims_20261106.sql(列已改名)。 -- -- ⚠️⚠️ join 键(v1 写错过,这里更正): -- service_subtask.inhospid 存的是 **pat_med_inhosp.inhospid**(业务主键),不是 id。 -- 证据:VisitInhospMapper.xml#selectForScan 查的是 b.inhospid; -- VisitSubtaskFactory 里是 d.setInhospid(inhosp.getInhospid())。 -- 门诊侧例外:PatMedOuthospServiceDelegatingImpl 用的是 pat_med_outhosp.getId(), -- 所以 pat_med_outhosp 的 id 会和 pat_med_inhosp.inhospid 撞号 → 必须排除 service_type='3'。 -- -- 字段映射(8 列,注意「在院病区」和「出院病区」不是一回事) -- 在院维度(本次新增列) -- service_subtask.hospitaldistrictcode/name ← pat_med_inhosp.hospitaldistrictcode/name (在院病区) -- service_subtask.deptcode/name ← pat_med_inhosp.deptcode/name (在院科室) -- 离院/出院维度(老列,原 deptcode/deptname 改名而来) -- service_subtask.leaveldeptcode/name ← pat_med_inhosp.leaveldeptcode/name (出院科室) -- service_subtask.leavehospitaldistrictcode/name ← pat_med_inhosp.leavehospitaldistrictcode/name (出院病区) -- -- 安全策略 -- 1) 全部用 COALESCE「目标列为空才写」→ **不覆盖任何已有值**,可重复执行; -- 2) 更新前先备份受影响行的这 8 列旧值(§2); -- 3) 大表分批模板见 §6。 -- ============================================================================ -- ---------------------------------------------------------------------------- -- 0) 前置自查 -- ---------------------------------------------------------------------------- SHOW FULL COLUMNS FROM service_subtask LIKE '%dept%'; SHOW FULL COLUMNS FROM service_subtask LIKE 'hospitaldistrict%'; SHOW FULL COLUMNS FROM pat_med_inhosp LIKE '%dept%'; SHOW FULL COLUMNS FROM pat_med_inhosp LIKE 'hospitaldistrict%'; -- ---------------------------------------------------------------------------- -- 1) 影响面评估(先看数,再动手) -- ---------------------------------------------------------------------------- -- 1.1 能 join 上的子任务数 + 8 列里各有多少是空的 SELECT COUNT(*) AS joined_rows, SUM(hospitaldistrictcode IS NULL OR hospitaldistrictcode = '') AS hd_code_empty, SUM(hospitaldistrictname IS NULL OR hospitaldistrictname = '') AS hd_name_empty, SUM(deptcode IS NULL OR deptcode = '') AS dept_code_empty, SUM(deptname IS NULL OR deptname = '') AS dept_name_empty, SUM(leaveldeptcode IS NULL OR leaveldeptcode = '') AS lv_dept_code_empty, SUM(leaveldeptname IS NULL OR leaveldeptname = '') AS lv_dept_name_empty, SUM(leavehospitaldistrictcode IS NULL OR leavehospitaldistrictcode = '') AS lv_hd_code_empty, SUM(leavehospitaldistrictname IS NULL OR leavehospitaldistrictname = '') AS lv_hd_name_empty FROM service_subtask s JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid WHERE s.inhospid IS NOT NULL AND s.service_type <> '3' AND (s.hosp_type IS NULL OR s.hosp_type <> '8'); -- 1.2 按 service_type 看分布(2/13 出院随访、17/18 入院宣教/入院随访、6/14/15/16 满意度子任务) SELECT s.service_type, COUNT(*) AS cnt, SUM(s.deptcode IS NULL OR s.deptcode = '') AS dept_empty, SUM(s.hospitaldistrictcode IS NULL OR s.hospitaldistrictcode = '') AS hd_empty, SUM(s.leaveldeptcode IS NULL OR s.leaveldeptcode = '') AS lv_dept_empty, SUM(s.leavehospitaldistrictcode IS NULL OR s.leavehospitaldistrictcode = '') AS lv_hd_empty FROM service_subtask s JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid WHERE s.inhospid IS NOT NULL AND s.service_type <> '3' GROUP BY s.service_type ORDER BY cnt DESC; -- 1.3 join 不上的诊断:inhospid 有值、但 patid 对不上 SELECT s.service_type, COUNT(*) AS unmatched FROM service_subtask s LEFT JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid WHERE s.inhospid IS NOT NULL AND s.service_type <> '3' AND b.inhospid IS NULL GROUP BY s.service_type ORDER BY unmatched DESC; -- 1.4 源表 inhospid 是否唯一(不唯一会让 UPDATE 取到其中一行,结果不确定) SELECT inhospid, COUNT(*) AS c, COUNT(DISTINCT patid) AS pats FROM pat_med_inhosp WHERE inhospid IS NOT NULL GROUP BY inhospid HAVING c > 1 ORDER BY c DESC LIMIT 20; -- 1.5 一条子任务是否会被多行源数据命中(应为 0;有值就先把 §1.4 的重复处理干净) SELECT COUNT(*) AS subtask_rows, COUNT(*) - COUNT(DISTINCT s.id) AS dup_hit FROM service_subtask s JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid WHERE s.inhospid IS NOT NULL AND s.service_type <> '3'; -- ---------------------------------------------------------------------------- -- 2) 备份受影响行的 8 列旧值(回滚见 §7) -- ---------------------------------------------------------------------------- CREATE TABLE bak_service_subtask_dept_20261106 AS SELECT s.id, s.service_type, s.hosp_type, s.inhospid, s.patid, s.leaveldeptcode, s.leaveldeptname, s.leavehospitaldistrictcode, s.leavehospitaldistrictname, s.hospitaldistrictcode, s.hospitaldistrictname, s.deptcode, s.deptname FROM service_subtask s JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid WHERE s.inhospid IS NOT NULL AND s.service_type <> '3' AND (s.hosp_type IS NULL OR s.hosp_type <> '8') AND ( NULLIF(TRIM(s.hospitaldistrictcode), '') IS NULL OR NULLIF(TRIM(s.hospitaldistrictname), '') IS NULL OR NULLIF(TRIM(s.deptcode), '') IS NULL OR NULLIF(TRIM(s.deptname), '') IS NULL OR NULLIF(TRIM(s.leaveldeptcode), '') IS NULL OR NULLIF(TRIM(s.leaveldeptname), '') IS NULL OR NULLIF(TRIM(s.leavehospitaldistrictcode), '') IS NULL OR NULLIF(TRIM(s.leavehospitaldistrictname), '') IS NULL ); SELECT COUNT(*) AS backup_rows FROM bak_service_subtask_dept_20261106; -- ---------------------------------------------------------------------------- -- 3) 主回填:在院 4 列 + 离院 4 列(只补空,不覆盖;可重复执行) -- ---------------------------------------------------------------------------- UPDATE service_subtask s JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid SET s.hospitaldistrictcode = COALESCE(NULLIF(TRIM(s.hospitaldistrictcode), ''), b.hospitaldistrictcode), s.hospitaldistrictname = COALESCE(NULLIF(TRIM(s.hospitaldistrictname), ''), b.hospitaldistrictname), s.deptcode = COALESCE(NULLIF(TRIM(s.deptcode), ''), b.deptcode), s.deptname = COALESCE(NULLIF(TRIM(s.deptname), ''), b.deptname), s.leaveldeptcode = COALESCE(NULLIF(TRIM(s.leaveldeptcode), ''), b.leaveldeptcode), s.leaveldeptname = COALESCE(NULLIF(TRIM(s.leaveldeptname), ''), b.leaveldeptname), s.leavehospitaldistrictcode = COALESCE(NULLIF(TRIM(s.leavehospitaldistrictcode), ''), b.leavehospitaldistrictcode), s.leavehospitaldistrictname = COALESCE(NULLIF(TRIM(s.leavehospitaldistrictname), ''), b.leavehospitaldistrictname) WHERE s.inhospid IS NOT NULL AND s.service_type <> '3' -- 门诊随访的 inhospid 是 pat_med_outhosp.id AND (s.hosp_type IS NULL OR s.hosp_type <> '8') -- 扫码生成的虚拟患者 AND ( NULLIF(TRIM(s.hospitaldistrictcode), '') IS NULL OR NULLIF(TRIM(s.hospitaldistrictname), '') IS NULL OR NULLIF(TRIM(s.deptcode), '') IS NULL OR NULLIF(TRIM(s.deptname), '') IS NULL OR NULLIF(TRIM(s.leaveldeptcode), '') IS NULL OR NULLIF(TRIM(s.leaveldeptname), '') IS NULL OR NULLIF(TRIM(s.leavehospitaldistrictcode), '') IS NULL OR NULLIF(TRIM(s.leavehospitaldistrictname), '') IS NULL ); -- ---------------------------------------------------------------------------- -- 4) 口径说明 + 可选的"强制改写" -- -- 4.1 为什么离院 4 列也用「只补空」: -- service_type = 17/18(入院宣教/入院随访)生成时走 type 4/5 分支, -- `leaveldeptcode/name` 里存的其实是**入院科室**(d.setLeaveldeptcode(inhosp.getDeptcode()))。 -- 这些行非空 → §3 不会动它们;若为空则会被补成 pat_med_inhosp.leaveldeptcode -- (住院患者通常为空 → 等于没变)。 -- 出院随访(2/13)与满意度子任务(6/14/15/16)的离院 4 列生成时本来就取自 -- pat_med_inhosp,只可能是历史脏数据为空,补空即修数据。 -- -- 4.2 如果你要的是"17/18 也统一成出院科室口径",用下面这段(**会覆盖**,先跑 §2 备份): -- ---------------------------------------------------------------------------- -- UPDATE service_subtask s -- JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid -- SET s.leaveldeptcode = b.leaveldeptcode, -- s.leaveldeptname = b.leaveldeptname, -- s.leavehospitaldistrictcode = b.leavehospitaldistrictcode, -- s.leavehospitaldistrictname = b.leavehospitaldistrictname -- WHERE s.inhospid IS NOT NULL -- AND s.service_type IN ('17', '18') -- AND (NULLIF(TRIM(b.leaveldeptcode), '') IS NOT NULL -- OR NULLIF(TRIM(b.leavehospitaldistrictcode), '') IS NOT NULL); -- ---------------------------------------------------------------------------- -- 5) 【可选】全都强制覆盖版("原来有值但是错的"时用) -- 把 §3 的 COALESCE(...) 换成直接赋值,并去掉 WHERE 里那串「目标列为空」条件: -- SET s.hospitaldistrictcode = b.hospitaldistrictcode, -- s.hospitaldistrictname = b.hospitaldistrictname, -- s.deptcode = b.deptcode, s.deptname = b.deptname, -- s.leaveldeptcode = b.leaveldeptcode, s.leaveldeptname = b.leaveldeptname, -- s.leavehospitaldistrictcode = b.leavehospitaldistrictcode, -- s.leavehospitaldistrictname = b.leavehospitaldistrictname -- ⚠️ pat_med_inhosp.dept* 会被「在院信息刷新」定时任务按 HIS 当前科室改写, -- 覆盖后可能把"出院当时的科室"改成"现在 HIS 里的科室"。覆盖前务必先备份。 -- ---------------------------------------------------------------------------- -- ---------------------------------------------------------------------------- -- 6) 大表分批模板(多表 UPDATE 不支持 LIMIT,用 id 区间;每段单独提交) -- 先查范围:SELECT MIN(id), MAX(id) FROM service_subtask; -- ---------------------------------------------------------------------------- -- UPDATE service_subtask s -- JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid -- SET s.hospitaldistrictcode = COALESCE(NULLIF(TRIM(s.hospitaldistrictcode), ''), b.hospitaldistrictcode), -- s.hospitaldistrictname = COALESCE(NULLIF(TRIM(s.hospitaldistrictname), ''), b.hospitaldistrictname), -- s.deptcode = COALESCE(NULLIF(TRIM(s.deptcode), ''), b.deptcode), -- s.deptname = COALESCE(NULLIF(TRIM(s.deptname), ''), b.deptname), -- s.leaveldeptcode = COALESCE(NULLIF(TRIM(s.leaveldeptcode), ''), b.leaveldeptcode), -- s.leaveldeptname = COALESCE(NULLIF(TRIM(s.leaveldeptname), ''), b.leaveldeptname), -- s.leavehospitaldistrictcode = COALESCE(NULLIF(TRIM(s.leavehospitaldistrictcode), ''), b.leavehospitaldistrictcode), -- s.leavehospitaldistrictname = COALESCE(NULLIF(TRIM(s.leavehospitaldistrictname), ''), b.leavehospitaldistrictname) -- WHERE s.id > 1 AND s.id <= 50000 -- AND s.inhospid IS NOT NULL -- AND s.service_type <> '3' -- AND (s.hosp_type IS NULL OR s.hosp_type <> '8') -- AND ( NULLIF(TRIM(s.hospitaldistrictcode), '') IS NULL -- OR NULLIF(TRIM(s.hospitaldistrictname), '') IS NULL -- OR NULLIF(TRIM(s.deptcode), '') IS NULL -- OR NULLIF(TRIM(s.deptname), '') IS NULL -- OR NULLIF(TRIM(s.leaveldeptcode), '') IS NULL -- OR NULLIF(TRIM(s.leaveldeptname), '') IS NULL -- OR NULLIF(TRIM(s.leavehospitaldistrictcode), '') IS NULL -- OR NULLIF(TRIM(s.leavehospitaldistrictname), '') IS NULL ); -- ---------------------------------------------------------------------------- -- 7) 回滚(按 §2 备份表还原 8 列) -- ---------------------------------------------------------------------------- -- UPDATE service_subtask s -- JOIN bak_service_subtask_dept_20261106 k ON k.id = s.id -- SET s.hospitaldistrictcode = k.hospitaldistrictcode, -- s.hospitaldistrictname = k.hospitaldistrictname, -- s.deptcode = k.deptcode, -- s.deptname = k.deptname, -- s.leaveldeptcode = k.leaveldeptcode, -- s.leaveldeptname = k.leaveldeptname, -- s.leavehospitaldistrictcode = k.leavehospitaldistrictcode, -- s.leavehospitaldistrictname = k.leavehospitaldistrictname; -- ---------------------------------------------------------------------------- -- 8) 回填后核对 -- ---------------------------------------------------------------------------- -- 8.1 还剩多少空(应接近 0;剩下的基本是 §1.3/§1.4 命中不了的) SELECT COUNT(*) AS still_empty_rows, SUM(hospitaldistrictcode IS NULL OR hospitaldistrictcode = '') AS hd_code_empty, SUM(hospitaldistrictname IS NULL OR hospitaldistrictname = '') AS hd_name_empty, SUM(deptcode IS NULL OR deptcode = '') AS dept_code_empty, SUM(deptname IS NULL OR deptname = '') AS dept_name_empty, SUM(leaveldeptcode IS NULL OR leaveldeptcode = '') AS lv_dept_code_empty, SUM(leaveldeptname IS NULL OR leaveldeptname = '') AS lv_dept_name_empty, SUM(leavehospitaldistrictcode IS NULL OR leavehospitaldistrictcode = '') AS lv_hd_code_empty, SUM(leavehospitaldistrictname IS NULL OR leavehospitaldistrictname = '') AS lv_hd_name_empty FROM service_subtask s JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid WHERE s.inhospid IS NOT NULL AND s.service_type <> '3' AND (s.hosp_type IS NULL OR s.hosp_type <> '8') AND ( NULLIF(TRIM(s.hospitaldistrictcode), '') IS NULL OR NULLIF(TRIM(s.hospitaldistrictname), '') IS NULL OR NULLIF(TRIM(s.deptcode), '') IS NULL OR NULLIF(TRIM(s.deptname), '') IS NULL OR NULLIF(TRIM(s.leaveldeptcode), '') IS NULL OR NULLIF(TRIM(s.leaveldeptname), '') IS NULL OR NULLIF(TRIM(s.leavehospitaldistrictcode), '') IS NULL OR NULLIF(TRIM(s.leavehospitaldistrictname), '') IS NULL ); -- 8.2 逐行对照抽检(两边是否一致) SELECT s.id, s.service_type, s.inhospid, s.deptcode AS sub_dept, b.deptcode AS inhosp_dept, s.hospitaldistrictcode AS sub_hd, b.hospitaldistrictcode AS inhosp_hd, s.leaveldeptcode AS sub_lv_dept, b.leaveldeptcode AS inhosp_lv_dept, s.leavehospitaldistrictcode AS sub_lv_hd, b.leavehospitaldistrictcode AS inhosp_lv_hd FROM service_subtask s JOIN pat_med_inhosp b ON b.inhospid = s.inhospid AND b.patid = s.patid WHERE s.inhospid IS NOT NULL AND s.service_type <> '3' ORDER BY s.id DESC LIMIT 50;