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

递归CTE还是ROW_NUMBER分区?SQL按状态重置计数实现问题

解决连续相同值分组的计数重置问题

我懂你遇到的问题了——你需要按CDO_OP_REFERRAL_UNIQUE_ID分组,每当ATTENDED_OR_DID_NOT_ATTEND的取值发生变化时,就把计数重置为1;如果是连续相同的取值,就让计数递增。这属于SQL里经典的岛屿与缺口问题,单纯用ROW_NUMBER() OVER(PARTITION BY ...)确实搞不定,因为它没法识别连续的相同值“岛屿”。

解决方案思路

我们需要先给每一组连续相同的ATTENDED_OR_DID_NOT_ATTEND值分配一个唯一的分组ID,然后在每个分组内使用ROW_NUMBER()来生成递增计数:

  1. 使用LAG()函数获取当前行的上一行ATTENDED_OR_DID_NOT_ATTEND值,和当前行对比,若不同则标记为1(表示新分组开始),否则标记为0。
  2. 用SUM() OVER()累加这些标记值,得到每个连续相同值组的分组ID。
  3. 最后在CDO_OP_REFERRAL_UNIQUE_ID和分组ID的分区内,用ROW_NUMBER()生成你需要的计数结果。

完整SQL代码

DECLARE @CDO_OP_APPOINTMENT TABLE (
    CDO_OP_REFERRAL_UNIQUE_ID int,
    LOCAL_PATIENT_NUMBER varchar(10),
    APPOINTMENT_START_DATE_TIME datetime,
    ATTENDED_OR_DID_NOT_ATTEND varchar(10),
    DESIRED_OUTCOME varchar(10)
) 

INSERT INTO @CDO_OP_APPOINTMENT VALUES 
('480805568', 'HEY1030785', '05/11/2013 10:00', '2', '1'), 
('480805568', 'HEY1030785', '12/11/2013 10:00', '5', '1'), 
('480805568', 'HEY1030785', '22/11/2013 09:30', '5', '2'), 
('480805568', 'HEY1030785', '03/12/2013 13:00', '3', '1'), 
('480805568', 'HEY1030785', '30/12/2013 10:15', '5', '1'), 
('480805568', 'HEY1030785', '24/02/2014 09:15', '4', '1'), 
('480805568', 'HEY1030785', '24/02/2014 14:15', '5', '1'), 
('480805568', 'HEY1030785', '17/03/2014 15:25', '4', '1'), 
('480805568', 'HEY1030785', '20/03/2014 18:50', '5', '1'), 
('480805568', 'HEY1030785', '23/09/2014 15:55', '5', '2'), 
('480805568', 'HEY1030785', '14/04/2015 16:30', '5', '3'), 
('480805568', 'HEY1030785', '14/04/2015 17:30', '4', '1'), 
('480805568', 'HEY1030785', '15/05/2015 14:15', '5', '1')

-- 核心查询部分
SELECT 
    CDO_OP_REFERRAL_UNIQUE_ID,
    LOCAL_PATIENT_NUMBER,
    APPOINTMENT_START_DATE_TIME,
    ATTENDED_OR_DID_NOT_ATTEND,
    DESIRED_OUTCOME,
    -- 生成符合要求的计数
    ROW_NUMBER() OVER(
        PARTITION BY CDO_OP_REFERRAL_UNIQUE_ID, GroupId 
        ORDER BY APPOINTMENT_START_DATE_TIME
    ) AS CALCULATED_OUTCOME
FROM (
    SELECT 
        *,
        -- 生成连续相同值的分组ID
        SUM(GroupStartFlag) OVER(
            PARTITION BY CDO_OP_REFERRAL_UNIQUE_ID 
            ORDER BY APPOINTMENT_START_DATE_TIME
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        ) AS GroupId
    FROM (
        SELECT 
            *,
            -- 判断当前行是否是新分组的开始
            CASE WHEN LAG(ATTENDED_OR_DID_NOT_ATTEND) OVER(
                PARTITION BY CDO_OP_REFERRAL_UNIQUE_ID 
                ORDER BY APPOINTMENT_START_DATE_TIME
            ) != ATTENDED_OR_DID_NOT_ATTEND THEN 1 ELSE 0 END AS GroupStartFlag
        FROM @CDO_OP_APPOINTMENT
    ) AS FlaggedRows
) AS GroupedRows
ORDER BY APPOINTMENT_START_DATE_TIME

结果验证

运行以上代码后,CALCULATED_OUTCOME列的值会和你提供的DESIRED_OUTCOME完全一致,完美实现了“每当ATTENDED_OR_DID_NOT_ATTEND变化时重置计数”的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:27:16