assets/2026-07-01-医数智联系列开篇-医院数字化工作者的工具箱_2026-07-01_18-28-11.jpg

[!ABSTRACT] 核心摘要

  • 本期主题:把第 07、08 期的 SQL 技能串起来,从「写查询」到「出一份院长能直接看的月度主诊错误率报告」
  • 核心结论:首页主诊错误率 = 主诊错误病案数 / 总病案数 × 100%,但真正的实战要回答 5 个 Why
  • 5 大分析维度:总量、科室、医生、错误类型、时间趋势
  • 5 步分析流程:数据提取 → 总体统计 → 维度下钻 → 错误归因 → 报告输出
  • 阅读时长:约 10 分钟

一、场景引入:院长要「一份错误率报告」,背后要回答的 5 个 Why

[!example] 一个真实的周一早晨
院长办公室,周一 8 点 30。

院长:「上月首页主诊错误率多少?」

质管办小张:「2.3%。」(他自己刚跑的数据)

院长:「哪个科室最高?」

小张:「骨科。」

院长:「为什么?

小张:「……我查一下。」

1 小时后,小张回复:

「骨科错误数 28 条,其中主诊未选主要诊断 18 条,占比 64%;主诊 ICD 编码错误 10 条,占比 36%。责任医生 Top 3 是李医生、张医生、王医生,都是高年资主治。」

院长:「怎么改?

小张:「……我再想想。」

院长要的不是「一个数字」,而是一个完整的分析故事:

Why 问题 数据维度
Why 1 上月错误率多少? 总体统计
Why 2 哪个科室最高? 科室维度
Why 3 哪些医生是高发? 医生维度
Why 4 主要错误类型是什么? 错误归因
Why 5 趋势是升是降? 时间趋势

[!quote] 狼叔的判断
“一份合格的主诊错误率报告,不是’一个数字’,而是’一个故事’。” 这一期,带你用 5 步流程,跑出完整的月度分析。


二、工具原理:首页主诊错误率分析的核心思路

2.1 关键指标定义

[!info] 核心指标
首页主诊错误率 = 主诊错误病案数 / 总出院病案数 × 100%

配套指标:

  • 绝对错误数:主诊错误病案数(条)
  • 错误类型分布:各类错误占总数的比例
  • 责任医生分布:Top N 医生 + 错误数
  • 科室分布:各科室错误率对比

2.2 数据源说明

[!TIP] 医院常见数据源(假设表结构)

表名 关键字段 说明
首页主表 病案号、出院日期、科室、责任医生工号、主诊 ICD、主诊错误标记 病案首页主表
医生表 医生工号、医生姓名、职称、所属科室 医生主数据
错误代码表 错误代码、错误描述、错误类型 错误类型字典
病案审核表 病案号、审核日期、错误代码、错误分值 审核记录

[!warning] 实际表名和字段名以你院 HIS 系统为准
下面的 SQL 用了通用命名,实际用时改成你院的真实表名

2.3 5 步分析流程

[!example] 5 步流程

  1. Step 1:数据提取 —— 锁定时间范围,提取主诊错误的病案
  2. Step 2:总体统计 —— 总错误数、总错误率
  3. Step 3:维度下钻 —— 按科室、医生、错误类型拆分
  4. Step 4:错误归因 —— 找 Top 错误类型,找 Top 医生
  5. Step 5:趋势分析 —— 对比上月/去年同期

三、医院实战:5 步完整 SQL

Step 1:数据提取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
-- 上月所有出院病案(主表数据)
CREATE TEMPORARY TABLE tmp_上月出院 AS
SELECT
病案号,
出院日期,
科室,
责任医生工号,
主诊ICD,
主诊错误标记
FROM 首页主表
WHERE 出院日期 >= '2026-06-01'
AND 出院日期 < '2026-07-01';

-- 上月主诊错误的病案(带错误详情)
CREATE TEMPORARY TABLE tmp_上月错误 AS
SELECT
a.病案号,
a.出院日期,
a.科室,
a.责任医生工号,
b.错误代码,
c.错误描述,
c.错误类型,
b.错误分值,
b.审核日期
FROM 首页主表 a
INNER JOIN 病案审核表 b ON a.病案号 = b.病案号
LEFT JOIN 错误代码表 c ON b.错误代码 = c.错误代码
WHERE a.主诊错误标记 = 1
AND a.出院日期 >= '2026-06-01'
AND a.出院日期 < '2026-07-01';

[!TIP] 用 TEMPORARY TABLE 暂存中间结果
避免反复跑同一段 SQL,性能提升 3-5 倍

Step 2:总体统计

1
2
3
4
5
6
-- 总体错误率
SELECT
COUNT(*) AS 总病案数,
SUM(主诊错误标记) AS 错误病案数,
ROUND(SUM(主诊错误标记) * 100.0 / COUNT(*), 2) AS 错误率_百分比
FROM tmp_上月出院;

典型输出:

1
2
| 总病案数 | 错误病案数 | 错误率_百分比 |
| 3250 | 75 | 2.31 |

Step 3a:科室维度下钻

1
2
3
4
5
6
7
8
SELECT
科室,
COUNT(DISTINCT 病案号) AS 总病案数,
SUM(主诊错误标记) AS 错误数,
ROUND(SUM(主诊错误标记) * 100.0 / COUNT(DISTINCT 病案号), 2) AS 错误率_百分比
FROM tmp_上月出院
GROUP BY 科室
ORDER BY 错误率_百分比 DESC;

典型输出:

1
2
3
4
| 科室   | 总病案数 | 错误数 | 错误率_百分比 |
| 骨科 | 280 | 28 | 10.00 |
| 神经科 | 195 | 15 | 7.69 |
| 消化科 | 220 | 12 | 5.45 |

Step 3b:医生维度下钻(Top 10)

1
2
3
4
5
6
7
8
9
10
11
SELECT
a.责任医生工号,
b.医生姓名,
b.职称,
a.科室,
COUNT(*) AS 错误数
FROM tmp_上月错误 a
LEFT JOIN 医生表 b ON a.责任医生工号 = b.医生工号
GROUP BY a.责任医生工号, b.医生姓名, b.职称, a.科室
ORDER BY 错误数 DESC
LIMIT 10;

典型输出:

1
2
3
4
| 医生工号 | 医生姓名 | 职称     | 科室 | 错误数 |
| D001 | 李医生 | 主治医师 | 骨科 | 12 |
| D002 | 张医生 | 主治医师 | 骨科 | 9 |
| D003 | 王医生 | 副主任 | 神经科 | 8 |

Step 3c:错误类型维度下钻

1
2
3
4
5
6
7
8
SELECT
错误类型,
错误描述,
COUNT(*) AS 错误数,
ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (), 2) AS 占比百分比
FROM tmp_上月错误
GROUP BY 错误类型, 错误描述
ORDER BY 错误数 DESC;

典型输出:

1
2
3
4
5
| 错误类型       | 错误描述             | 错误数 | 占比百分比 |
| 主诊选择错误 | 主诊未选主要诊断 | 45 | 60.00 |
| ICD 编码错误 | 主诊 ICD 与性别不符 | 18 | 24.00 |
| 手术编码错误 | 手术 ICD 与操作不符 | 8 | 10.67 |
| 其他 | 其他错误 | 4 | 5.33 |

Step 4:错误归因 + Top 医生

[!example] 实战:把「错误类型 × 责任医生」交叉分析
这一步是回答院长的「为什么」的关键。

1
2
3
4
5
6
7
8
9
10
11
SELECT
a.责任医生工号,
b.医生姓名,
c.错误类型,
COUNT(*) AS 错误数
FROM tmp_上月错误 a
LEFT JOIN 医生表 b ON a.责任医生工号 = b.医生工号
LEFT JOIN 错误代码表 c ON a.错误代码 = c.错误代码
GROUP BY a.责任医生工号, b.医生姓名, c.错误类型
ORDER BY 错误数 DESC
LIMIT 20;

典型发现:

  • 李医生的 12 条错误中,8 条是「主诊未选主要诊断」——说明是诊断选择习惯问题;
  • 张医生的 9 条错误中,6 条是「主诊 ICD 与性别不符」——说明是编码规范性问题。

Step 5:趋势分析(对比上月 + 去年同期)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
WITH 本月 AS (
SELECT COUNT(*) AS 总数, SUM(主诊错误标记) AS 错误数
FROM 首页主表
WHERE 出院日期 >= '2026-07-01' AND 出院日期 < '2026-08-01'
),
上月 AS (
SELECT COUNT(*) AS 总数, SUM(主诊错误标记) AS 错误数
FROM 首页主表
WHERE 出院日期 >= '2026-06-01' AND 出院日期 < '2026-07-01'
),
去年同月 AS (
SELECT COUNT(*) AS 总数, SUM(主诊错误标记) AS 错误数
FROM 首页主表
WHERE 出院日期 >= '2025-07-01' AND 出院日期 < '2025-08-01'
)
SELECT
ROUND(本月.错误数 / 本月.总数 * 100, 2) AS 本月错误率,
ROUND(上月.错误数 / 上月.总数 * 100, 2) AS 上月错误率,
ROUND(去年同月.错误数 / 去年同月.总数 * 100, 2) AS 去年同月错误率,
ROUND((本月.错误数 / 本月.总数 - 上月.错误数 / 上月.总数) * 100, 2) AS 环比变化_百分点,
ROUND((本月.错误数 / 本月.总数 - 去年同月.错误数 / 去年同月.总数) * 100, 2) AS 同比变化_百分点
FROM 本月, 上月, 去年同月;

四、避坑指南:5 个真实业务中容易踩的坑

[!warning] 雷区 ①:用 COUNT(*) 而不是 COUNT(DISTINCT 病案号)
症状:一份病案有 2 条审核记录时,错误数被算成 2。
解决:COUNT(DISTINCT 病案号) 去重

[!warning] 雷区 ②:百分比忘记乘 100
症状:错误率 显示 0.023,应该是 2.3%
解决:乘以 100.0(整数除法会丢精度)。

[!warning] 雷区 ③:对全院统计时忘记排除「日间手术」「死亡病案」
症状:把日间手术也算进错误率,基数被拉低,数字失真。
解决:明确统计口径,建议在 SQL 里加 WHERE 病案类型 = '常规住院'

[!warning] 雷区 ④:JOIN 后字段名歧义
症状:多张表都有 科室 字段,SQL 报 ambiguous(模糊)。
解决:所有字段加表别名:a.科室b.科室

[!warning] 雷区 ⑤:跑大数据量 SQL 不加 LIMIT
症状:SQL 跑了 10 分钟还没出来。
解决:先用 LIMIT 100 调试,确认逻辑后再放开


五、把 SQL 输出变「报告」

[!TIP] 报告输出 3 种方式

方式 ①:直接复制到 Excel
GUI 工具 → 运行 SQL → 结果集 → 右键「导出 CSV」 → 打开 Excel 排版

方式 ②:用 Navicat 定时邮件
配置「查询计划」→ 设置每日/每周定时 → 自动发送邮件

方式 ③:Python 自动生成 PDF(后续第 20 期讲)
用 pandas 处理 SQL 结果 + matplotlib 画图 + reportlab 输出 PDF


六、下期预告

[!quote] 第 10 期
MySQL + DRG 入组异常筛查 —— 让医保结算少扣钱

讲怎么用 SQL 找出 DRG 入组异常病例(低码高套、误入组、歧义病例),这是医保结算的「关键防线」。


[!TIP] 互动
如果你觉得这篇「医数智联·第 09 期」对你有用,请点赞、在看、转发给科里的同事。

我是白衣狼,一个用数字化工具把医院管理做「轻」的实战派。咱们下期见。