You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQL Server 2016基于模糊条件合并患者就诊记录为就医旅程

解决方案:SQL Server 2016整合患者连续就诊旅程

核心思路

通过分组连续就诊区间的方式,先给每个患者的就诊记录按入院日期排序,判断当前就诊与前一次就诊的日期是否相近,将同一段连续旅程的记录标记为同一组,再对每组进行聚合或列转行处理,得到每行代表一段就医旅程的结果。

步骤1:定义日期相近阈值

首先确定“日期相近”的业务标准,比如出院后7天内入院算同一段旅程,用变量存储这个阈值:

DECLARE @Threshold INT = 7; -- 根据实际业务调整阈值,如出院后3天内入院则设为3
DECLARE @TableName NVARCHAR(128) = 'YourTableName'; -- 替换为你的实际表名

步骤2:分组标记就医旅程

使用窗口函数生成患者就诊排序,再通过累加判断结果生成旅程组ID(trip_id),同一旅程的记录会拥有相同的trip_id:

WITH RankedVisits AS (
    -- 按患者分组,按入院日期排序,生成就诊序号
    SELECT 
        pID,
        vID,
        vdStart,
        vdEnd,
        ROW_NUMBER() OVER (PARTITION BY pID ORDER BY vdStart) AS visit_seq
    FROM @TableName
),
TripGrouped AS (
    -- 生成旅程组ID:第一条记录直接新建组;后续记录若入院日期<=前次出院日期+阈值,归为同组,否则新建组
    SELECT 
        pID,
        vID,
        vdStart,
        vdEnd,
        visit_seq,
        SUM(
            CASE 
                WHEN visit_seq = 1 THEN 1 
                ELSE CASE WHEN vdStart <= LAG(vdEnd) OVER (PARTITION BY pID ORDER BY visit_seq) + @Threshold THEN 0 ELSE 1 END
            END
        ) OVER (PARTITION BY pID ORDER BY visit_seq) AS trip_id
    FROM RankedVisits
)

步骤3:聚合旅程记录(两种可选方式)

方式1:拼接就诊信息(适合就诊数不固定的场景)

将同一旅程的就诊ID、日期范围拼接成字符串,同时计算旅程的最早开始和最晚结束日期:

SELECT 
    pID,
    trip_id,
    MIN(vdStart) AS trip_start_date, -- 旅程的最早入院日期
    MAX(vdEnd) AS trip_end_date, -- 旅程的最晚出院日期
    -- 拼接该旅程的所有就诊ID
    STUFF(
        (SELECT ', ' + CAST(vID AS VARCHAR(50)) 
         FROM TripGrouped t2 
         WHERE t2.pID = t1.pID AND t2.trip_id = t1.trip_id 
         ORDER BY t2.visit_seq
         FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS linked_visit_ids,
    -- 拼接每个就诊的日期范围
    STUFF(
        (SELECT ', ' + CAST(vdStart AS VARCHAR(50)) + '~' + CAST(vdEnd AS VARCHAR(50)) 
         FROM TripGrouped t2 
         WHERE t2.pID = t1.pID AND t2.trip_id = t1.trip_id 
         ORDER BY t2.visit_seq
         FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS visit_date_ranges
FROM TripGrouped t1
GROUP BY pID, trip_id
ORDER BY pID, trip_start_date;

方式2:列转行生成多列(适合单独列展示每段就诊的场景)

如果需要将旅程内的每一次就诊单独列为一列(如vID1、vdStart1等),使用动态SQL自动生成对应列:

-- 获取每个旅程内的最大就诊数
DECLARE @MaxVisitCount INT;
SELECT @MaxVisitCount = MAX(trip_visit_seq)
FROM (
    SELECT ROW_NUMBER() OVER (PARTITION BY pID, trip_id ORDER BY visit_seq) AS trip_visit_seq
    FROM TripGrouped
) t;

-- 动态生成列定义
DECLARE @ColumnDefs NVARCHAR(MAX) = '';
DECLARE @i INT = 1;
WHILE @i <= @MaxVisitCount
BEGIN
    SET @ColumnDefs += CONCAT(
        'MAX(CASE WHEN trip_visit_seq = ', @i, ' THEN vID END) AS vID', @i, ',',
        'MAX(CASE WHEN trip_visit_seq = ', @i, ' THEN vdStart END) AS vdStart', @i, ',',
        'MAX(CASE WHEN trip_visit_seq = ', @i, ' THEN vdEnd END) AS vdEnd', @i, ','
    );
    SET @i += 1;
END;
SET @ColumnDefs = LEFT(@ColumnDefs, LEN(@ColumnDefs) - 1); -- 移除最后一个逗号

-- 生成并执行最终SQL
DECLARE @FinalSQL NVARCHAR(MAX) = CONCAT('
WITH RankedVisits AS (
    SELECT 
        pID,
        vID,
        vdStart,
        vdEnd,
        ROW_NUMBER() OVER (PARTITION BY pID ORDER BY vdStart) AS visit_seq
    FROM ', @TableName, '
),
TripGrouped AS (
    SELECT 
        pID,
        vID,
        vdStart,
        vdEnd,
        visit_seq,
        SUM(
            CASE 
                WHEN visit_seq = 1 THEN 1
                ELSE CASE WHEN vdStart <= LAG(vdEnd) OVER (PARTITION BY pID ORDER BY visit_seq) + ', @Threshold, ' THEN 0 ELSE 1 END
            END
        ) OVER (PARTITION BY pID ORDER BY visit_seq) AS trip_id
    FROM RankedVisits
),
TripVisitSequenced AS (
    SELECT 
        *,
        ROW_NUMBER() OVER (PARTITION BY pID, trip_id ORDER BY visit_seq) AS trip_visit_seq
    FROM TripGrouped
)
SELECT 
    pID,
    trip_id,
    MIN(vdStart) AS trip_start_date,
    MAX(vdEnd) AS trip_end_date,
    ', @ColumnDefs, '
FROM TripVisitSequenced
GROUP BY pID, trip_id
ORDER BY pID, trip_start_date;
');

EXEC sp_executesql @FinalSQL;

性能优化建议

为确保查询耗时不超过10分钟,建议在表上创建以下索引,加速窗口函数的分组和排序操作:

CREATE NONCLUSTERED INDEX IX_PatientVisits_PID_StartDate 
ON YourTableName (pID, vdStart) 
INCLUDE (vID, vdEnd);

内容的提问来源于stack exchange,提问作者Edge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 21:48:20