2. 临床数据模型与查询对象
临床数据复杂查询的第一步,不是写 SQL,而是把“临床世界里真实存在的东西”翻译成“数据库里可被连接、过滤、聚合的对象”。如果对象边界没划清,后面无论写多复杂的 JOIN,都会出现重复计数、时间错配、口径不一致的问题。本节围绕患者、就诊、诊断、用药、检验、检查六类核心实体,讲清它们各自代表什么、靠什么字段发生关系,以及查询时最容易踩的坑。
一、六个核心实体分别承载什么信息
患者(Patient)是身份主体,回答“这是谁”。关键字段通常包括患者主索引(patient_id)、院内病案号(mrn)、姓名、性别、出生日期、身份证号等。患者表是全局唯一的身份锚点,一次住院、多次门诊都挂在同一个 patient_id 下。查询“某患者全部诊疗记录”时,患者表是起点。
就诊(Encounter/Visit)是一次具体的医疗接触,回答“哪一次来院”。关键字段包括就诊号(visit_id/encounter_id)、患者ID、就诊类型(门诊/急诊/住院/体检)、入院时间、出院时间、科室、医生。就诊是临床数据的时间容器——诊断、用药、检验、检查几乎都发生在某一次就诊之内。区分“患者级”和“就诊级”是临床查询最核心的口径问题。
诊断(Diagnosis)回答“得了什么病”。字段包括诊断ID、就诊ID、诊断编码(ICD-10/ICD-9-CM)、诊断名称、诊断类型(入院诊断/出院诊断/主诊断/次诊断)、诊断时间。同一就诊可有多条诊断,主诊断与次诊断的区分直接影响统计口径。
用药(Medication Order)回答“用了什么药”。字段包括医嘱ID、就诊ID、药品编码、药品名称、剂量、给药途径、频次、开始时间、停止时间、医嘱状态。用药是典型的“时间区间型”数据,判断“某时刻是否在用药”必须做时间区间重叠计算,不能只看是否有记录。
检验(Lab Test)回答“化验结果是什么”。字段包括检验申请ID、就诊ID、检验项目编码、结果值、单位、参考范围、采样时间、报告时间。检验是“项目—结果”结构,一个申请单可含多个项目,查询时通常要按项目编码过滤并做数值比较。
检查(Examination/Procedure)回答“做了什么影像或功能检查”。字段包括检查ID、就诊ID、检查项目编码、检查名称、检查时间、报告结论。检查与检验的区别在于:检验产出数值型结果,检查产出描述型报告,二者查询方式不同。
二、实体之间的关系建模
六类实体构成一棵以患者为根、以就诊为枢纽的关系树:患者 1:N 就诊;就诊 1:N 诊断、1:N 用药、1:N 检验、1:N 检查。所有临床事件表都通过 visit_id 与就诊关联,再通过就诊的 patient_id 回溯到患者。这种“患者—就诊—事件”的三层结构,是临床数据仓库最通用的建模方式。
关系建模要明确三种连接路径:身份路径(patient_id 连接患者与就诊)、事件路径(visit_id 连接就诊与各事件表)、时间路径(事件时间落在就诊时间窗内)。前两条是显式外键,第三条是隐式约束,也是查询中最容易出错的地方。
三、查询口径:患者级、就诊级与事件级
同一份数据,按不同层级聚合会得到完全不同的结果。例如“糖尿病患者人数”,若按患者级去重统计 patient_id,得到的是人数;若按就诊级统计 visit_id,得到的是就诊人次;若按诊断记录条数统计,则同一患者多次就诊会被重复计数。写查询前必须先明确口径,并在 SQL 中体现:患者级用 COUNT(DISTINCT patient_id),就诊级用 COUNT(DISTINCT visit_id)。
另一个高频问题是“一次就诊内多个事件的时间对齐”。比如要查“入院 48 小时内使用某抗生素且该次住院诊断为肺炎”的患者,需要同时满足:诊断表存在肺炎 ICD 编码、用药表存在目标药品、用药开始时间在入院后 48 小时内。三个条件分别落在三张表,必须通过 visit_id 关联,并用时间条件约束,不能简单用 IN 子查询拼接。
四、一个可复用的查询对象清单
把上述实体整理成查询前必须确认的对象清单,可以直接作为建模与写查询的检查表:
| 实体 | 主键 | 关联键 | 时间字段 | 查询口径要点 |
|---|---|---|---|---|
| 患者 | patient_id | — | 出生日期 | 身份去重,患者级统计基准 |
| 就诊 | visit_id | patient_id | 入院/出院时间 | 就诊级统计基准,时间窗容器 |
| 诊断 | diag_id | visit_id | 诊断时间 | 区分主/次诊断,按 ICD 编码过滤 |
| 用药 | order_id | visit_id | 开始/停止时间 | 时间区间重叠判断,注意医嘱状态 |
| 检验 | lab_id | visit_id | 采样/报告时间 | 按项目编码过滤,数值比较需带单位 |
| 检查 | exam_id | visit_id | 检查时间 | 报告为文本,需关键词或编码匹配 |