2. OMOP CDM 核心表结构精讲

OMOP CDM 的设计哲学是“以患者为中心、以事件为记录单元”。理解核心表,不能只背字段名,而要抓住每张表回答的临床问题:PERSON 回答“这个人是谁”,OBSERVATION_PERIOD 回答“这个人在什么时间段内被观察”,VISIT_OCCURRENCE 回答“这个人何时来就诊、以什么方式就诊”,CONDITION_OCCURRENCE、DRUG_EXPOSURE、MEASUREMENT 则分别回答“诊断了什么、用了什么药、测出了什么值”。这六张表构成了队列构建最常用的主干。

先看 PERSON。它是患者维度的主表,一行代表一个自然人,主键是 person_id。关键字段包括 gender_concept_id、year_of_birth、month_of_birth、day_of_birth、race_concept_id、ethnicity_concept_id、location_id、provider_id、care_site_id。其中性别、种族等字段都指向标准概念,而不是直接存文本。例如性别不是存“男/女”,而是存 gender_concept_id = 8507(Male)或 8532(Female)。出生日期字段允许部分为空,因为很多真实数据只有出生年份。队列构建中,PERSON 常用于年龄计算、性别筛选和人口学分层。

OBSERVATION_PERIOD 是“观察窗口”表,一行代表某人在某段时间内被数据库持续观察。字段为 observation_period_id、person_id、observation_period_start_date、observation_period_end_date、period_type_concept_id。它不记录具体临床事件,而是定义“数据可信区间”。做队列时,如果患者事件落在观察期之外,通常不能纳入分析,否则会引入“未记录”与“未发生”的混淆。例如某患者观察期是 2018-01-01 至 2020-12-31,那么 2021 年的用药记录若存在,往往说明数据边界有问题,需要核查。

VISIT_OCCURRENCE 记录就诊事件,一行代表一次就诊或一次医疗接触。核心字段有 visit_occurrence_id、person_id、visit_concept_id、visit_start_date、visit_end_date、visit_type_concept_id、care_site_id、provider_id。就诊类型通过 visit_concept_id 区分,如住院、门诊、急诊、药房等。它常作为其他事件表的“容器”:CONDITION_OCCURRENCE、DRUG_EXPOSURE、MEASUREMENT 等表都带有 visit_occurrence_id,用于把事件挂到具体就诊上。这样就能回答“这次住院期间发生了哪些诊断、用了哪些药、做了哪些检查”。

CONDITION_OCCURRENCE 记录诊断或病情事件,一行代表某人在某段时间内存在某个病症。字段包括 condition_occurrence_id、person_id、condition_concept_id、condition_start_date、condition_end_date、condition_type_concept_id、visit_occurrence_id、provider_id。诊断编码通过 condition_concept_id 标准化,例如 2 型糖尿病对应某个标准 SNOMED 概念。队列中常用它做纳入条件,如“至少一次 2 型糖尿病诊断”。

DRUG_EXPOSURE 记录药物暴露,一行代表一次用药或一段用药。字段包括 drug_exposure_id、person_id、drug_concept_id、drug_exposure_start_date、drug_exposure_end_date、quantity、days_supply、refills、route_concept_id、visit_occurrence_id。这里要特别注意:days_supply 表示一次处方覆盖的天数,quantity 表示发药数量,二者含义不同。队列中常用它定义暴露组,如“首次使用二甲双胍后 90 天内”。

MEASUREMENT 记录结构化测量结果,一行代表一次检验或检查数值。字段包括 measurement_id、person_id、measurement_concept_id、measurement_date、value_as_number、value_as_concept_id、unit_concept_id、range_low、range_high、visit_occurrence_id。例如糖化血红蛋白 HbA1c 的 value_as_number 为 7.2,unit_concept_id 指向百分比单位。队列中常用于定义结局或基线特征,如“HbA1c 大于 7%”。

这些表之间通过 person_id 和 visit_occurrence_id 关联。PERSON 是根,OBSERVATION_PERIOD 定义时间边界,VISIT_OCCURRENCE 是事件容器,其余三张事件表通过外键挂接。理解这个层级,就能在写 SQL 时快速判断该从哪张表出发、用哪个字段连接。

OMOP CDM 核心表关联结构 PERSON 为根,OBSERVATION_PERIOD 定边界,VISIT_OCCURRENCE 为事件容器 PERSON person_id (PK) gender / birth / race OBSERVATION_PERIOD person_id (FK) start_date / end_date VISIT_OCCURRENCE visit_occurrence_id (PK) person_id / visit_concept_id CONDITION_OCCURRENCE condition_occurrence_id person_id / visit_occurrence_id condition_concept_id DRUG_EXPOSURE drug_exposure_id person_id / visit_occurrence_id drug_concept_id / days_supply MEASUREMENT measurement_id person_id / visit_occurrence_id value_as_number / unit_concept_id person_id person_id visit_occurrence_id visit_occurrence_id visit_occurrence_id person_id 关联 visit_occurrence_id 关联 PK = 主键,FK = 外键

从工程角度看,写队列 SQL 时通常先锁定 PERSON 和 OBSERVATION_PERIOD,再按需连接 VISIT_OCCURRENCE 与事件表。例如要构建“2019 年新诊断 2 型糖尿病且使用二甲双胍的成人队列”,可以先用 PERSON 计算年龄,用 OBSERVATION_PERIOD 限定观察窗口,用 CONDITION_OCCURRENCE 找首次诊断,再用 DRUG_EXPOSURE 找首次用药,最后用 MEASUREMENT 补充基线 HbA1c。每一步都要注意日期边界、概念 ID 和空值处理,否则队列规模会因“差一天”或“概念映射错误”而显著偏差。

记忆口诀:PERSON 是“人”,OBSERVATION_PERIOD 是“窗”,VISIT_OCCURRENCE 是“框”,CONDITION 是“病”,DRUG 是“药”,MEASUREMENT 是“值”。人窗框病药值,六表串起队列主干。