1. 临床研究队列构建工程导论

临床研究队列构建,本质上是把“临床问题”翻译成“可被数据库执行、可被统计软件消费、可被审阅者复核”的数据资产。它既不是单纯的 SQL 查询练习,也不是脱离数据结构的统计建模,而是一项横跨研究设计、数据工程与临床语义的交叉工作。本节先建立三个基础认知:队列研究有哪些设计类型、SQL 在真实世界数据(RWD)中扮演什么角色、以及如何把研究问题工程化为可执行 SQL。

一、队列研究的设计类型:先定“时间轴”,再定“比较结构”

队列研究的核心特征是“先暴露、后结局”的时序关系。按时间方向可分为三类:前瞻性队列在暴露发生后向前追踪结局,数据质量高但周期长;回顾性队列利用既有电子病历或理赔数据,从历史时点向后重建暴露与结局,是真实世界研究中最常见的形式;双向队列则结合两者,既回溯历史暴露,又向前补充随访。按比较结构又可分为暴露对照队列(如用药组 vs 未用药组)与单臂队列(仅描述某类患者的自然史或治疗模式)。

设计类型直接决定 SQL 中的三个关键量:索引日期(index date)、基线期(baseline period)与随访窗(follow-up window)。例如一项回顾性暴露对照队列,若以“首次使用二甲双胍”为索引事件,则基线期通常取索引日前 180 天用于评估合并症与既往用药,随访窗从索引日次日起算至结局事件、失访、死亡或研究截止日中最早发生者。这些定义一旦确定,就应固化为 SQL 中的日期参数,而不是散落在各段查询里。

二、SQL 在真实世界数据中的角色

真实世界数据通常分布在患者主索引、就诊记录、诊断、检验、处方/医嘱、生命体征等多张表中,且存在同一患者多次就诊、同一诊断多次记录、检验结果单位不统一等情况。SQL 在这里承担四类不可替代的职责:

  • 人群筛选:用诊断编码、药品编码、检验阈值等条件圈定目标人群,并施加年龄、性别、连续参保等纳入排除标准。
  • 时间对齐:把分散在不同表中的事件按患者和时间排序,计算索引日期、基线窗与随访窗,这是队列构建中最容易出错的部分。
  • 变量派生:把原始记录聚合为分析变量,如 Charlson 合并症指数、既往用药种类数、随访期间是否发生结局。
  • 可复现交付:以脚本形式保存全部逻辑,使队列可被重新生成、审计与版本管理。

需要强调的是,SQL 负责“把数据整理成分析就绪的宽表”,而生存分析、倾向性评分等统计推断仍由 R、Python 或 SAS 完成。二者边界清晰,才能避免在 SQL 中硬编码统计模型。

三、从研究问题到可执行 SQL 的工程化思维

工程化思维的关键,是把一句临床问题拆解为可验证的“结构化规格”。以“二甲双胍使用者相比磺脲类使用者,是否具有更低的 2 型糖尿病患者全因住院风险”为例,可拆解为如下规格:

规格项示例定义
目标人群18 岁及以上、确诊 2 型糖尿病、2019-01-01 至 2022-12-31 期间首次启用二甲双胍或磺脲类
索引日期首次处方日
暴露分组二甲双胍组 / 磺脲类组
基线期索引日前 365 天
随访窗索引日次日起至首次全因住院、死亡、失访或 2023-12-31
主要结局随访窗内首次全因住院
协变量年龄、性别、基线合并症、基线用药数

规格确定后,SQL 实现通常遵循“分层构建”而非“一条大查询”。推荐把脚本组织为若干可独立验证的 CTE 或临时表:cohort_base(候选人群)→ index_events(索引事件)→ baseline(基线特征)→ followup(随访与结局)→ analysis_ready(分析宽表)。每一层都可单独计数、抽样核对,从而把“结果不对”定位到具体环节。

-- 示例:索引事件层(示意,字段名按实际库表调整)
WITH index_events AS (
  SELECT patient_id,
         MIN(prescribe_date) AS index_date,
         CASE WHEN drug_code IN ('MET') THEN 'metformin'
              WHEN drug_code IN ('SU')  THEN 'sulfonylurea' END AS exposure
  FROM prescriptions
  WHERE drug_code IN ('MET','SU')
    AND prescribe_date BETWEEN '2019-01-01' AND '2022-12-31'
  GROUP BY patient_id, exposure
)
SELECT exposure, COUNT(DISTINCT patient_id) AS n
FROM index_events
GROUP BY exposure;

这段查询只解决“谁在何时进入队列”,但已经体现了工程化要点:用 MIN 取首次处方、用 CASE 明确暴露映射、用 GROUP BY 保证每位患者每个暴露组只保留一条索引记录。后续再与诊断表、住院表连接,即可逐步扩展为完整队列。

建议在脚本开头集中声明研究起止日期、基线窗长度、随访截止日等参数,并在注释中写明每个编码集的来源(如 ICD-10、ATC 或本地字典),便于复核与迁移。

四、本节知识结构总览

下图把“研究设计类型—SQL 职责—工程化落地”三者的关系压缩为一张结构图,帮助建立整体框架:左侧是设计选择,中间是 SQL 承担的数据加工职责,右侧是最终交付的分析就绪队列。

临床研究队列构建:设计 → SQL 加工 → 分析就绪 队列设计类型 前瞻性队列 暴露后向前追踪结局 回顾性队列 RWD 中最常见形式 双向队列 回溯 + 前瞻结合 暴露对照 / 单臂 决定比较结构 SQL 在 RWD 中的职责 ① 人群筛选 诊断 / 药品 / 检验 / 年龄 / 参保 ② 时间对齐 索引日 · 基线窗 · 随访窗 ③ 变量派生 合并症指数 · 用药数 · 结局标志 ④ 可复现交付 脚本化 · 可审计 · 版本管理 分层构建:base → index → baseline → followup 分析就绪队列 一行一患者 索引日 · 暴露 · 随访起止 结局与时间 事件标志 · 随访天数 协变量宽表 人口学 · 合并症 · 用药 交付给 R / Python / SAS 统计推断不在 SQL 内完成 规格 产出

把这张图记在脑中,后续每一节都可以定位到它的某个局部:设计类型决定时间轴,SQL 职责决定加工步骤,分析就绪队列决定最终交付形态。工程化的价值,正在于让这三者始终对齐、可追溯、可复现。