【问题标题】:SQL check change in status for ID month by monthSQL逐月检查ID的状态变化
【发布时间】:2025-11-25 01:00:01
【问题描述】:

我正在尝试每月查找患者风险级别的变化。使用下面的数据。我想看看 - 一个月内有多少患者的风险水平升高。例如:在下表中,截至 2021 年 5 月 9 日,John 的风险级别为“低”,而 2021 年 5 月 10 日风险增加到“高”。所以在 5 月,如果我为风险增加的患者创建条形图,我会算上 John

+----+------------+------------+----------------+
| ID | MemberName | Risk level | Discharge Date |
+----+------------+------------+----------------+
| 1  | John Doe   | Low        | 03/05/2021     |
+----+------------+------------+----------------+
| 1  | John Doe   | Medium     | 05/10/2021     |
+----+------------+------------+----------------+
| 1  | John Doe   | High       | 06/10/2021     |
+----+------------+------------+----------------+
| 2  | Sam        | Medium     | 05/10/2021     |
+----+------------+------------+----------------+
| 2  | Sam        | Low        | 05/20/2021     |
+----+------------+------------+----------------+

查询

SELECT [ID], [MemberName], [Risk level], [Discharge Date],
DATEADD(month, DATEDIFF(month, 0,  [Discharge Date]), 0) as StartOfMonth,
COUNT(*) OVER (PARTITION BY ID, MONTH([Discharge Date])) as Increase_Level
--Decrease level
from Member_Risk

预期输出

+----+------------+--------------+------------------------+------------------------+
| ID | MemberName | StartOfMonth | Increase_In_Risk_Level | Decrease_In_Risk_Level |
+----+------------+--------------+------------------------+------------------------+
| 1  | John Doe   | 03/01/2021   | No                     | No                     |
+----+------------+--------------+------------------------+------------------------+
| 1  | John Doe   | 05/01/2021   | Yes                    | No                     |
+----+------------+--------------+------------------------+------------------------+
| 1  | John Doe   | 06/01/2021   | Yes                    | No                     |
+----+------------+--------------+------------------------+------------------------+
| 2  | Sam        | 05/01/2021   | No                     | Yes                    |
+----+------------+--------------+------------------------+------------------------+

由于 Sam 将风险级别从“中”更改为“低”,即降低,因此 Decrease_In_Risk_Level 标志更新为“是”

【问题讨论】:

    标签: sql sql-server window-functions partition


    【解决方案1】:

    我创建了一个名为 riskScore 的虚拟列,它分配以下分数: 低 = 1,中 = 2,高 = 3

    此列用作与前几个月的比较。我使用 LAG() 收集前几个月的风险评分。一旦我有了前几个月的值,我会做一个案例陈述来比较riskcore和prior_risk,如下所示:

    WITH base as (
    SELECT 
        *, 
        CASE WHEN risklevel = 'Low' THEN 1 
        WHEN risklevel = 'Medium' THEN 2 
        WHEN risklevel = 'High' THEN 3 END AS RiskScore 
    FROM patient), 
    
    score as (
    SELECT 
       *, 
       LAG(riskscore) OVER (PARTITION BY id ORDER BY DischargeDt ASC) 
       AS prior_risk 
    FROM base)
    
    SELECT 
       *, 
      CASE WHEN prior_risk is NULL THEN NULL 
      WHEN riskscore > prior_risk THEN 'Increased' 
      ELSE 'Decreased' END AS status 
    FROM score
    

    注意:您的月初逻辑是正确的,如果需要,您可以将其添加到提供的逻辑中。此外,riskScore 和prior_score 列用于演示目的,您可以将其从最终输出中删除。

    【讨论】:

      【解决方案2】:

      使用窗口函数lag() over()

      您可能会注意到CASE 决定了增加/减少。理想情况下,您应该有一个数字风险评级,但这将适用于当前数据集。

      示例

      Declare @YourTable Table ([ID] int,[MemberName] varchar(50),[Risk level] varchar(50),[Discharge Date] date)
      Insert Into @YourTable Values 
       (1,'John Doe','Low','03/05/2021')
      ,(1,'John Doe','Medium','05/10/2021')
      ,(1,'John Doe','High','06/10/2021')
      ,(2,'Sam','Medium','05/10/2021')
      ,(2,'Sam','Low','05/20/2021')
      
      ;with cte as (
            Select * 
                  ,RiskLag = lag([Risk Level],1,[Risk Level]) over (partition by id order by [Discharge Date])
                  ,RN = row_number() over (partition by id,year([Discharge Date]),month([Discharge Date]) order by [Discharge Date] desc)
             From  @YourTable
      )
      Select ID
            ,MemberName
            ,StartOfMonth  = convert(date,dateadd(MONTH,datediff(MONTH,0,[Discharge Date]),0))
            ,Increase_Risk = case when right(RiskLag,1)>right([Risk level],1) 
                                  then 'Yes'
                                  else 'No'
                             end
            ,Derease_Risk = case when right(RiskLag,1)<right([Risk level],1) 
                                  then 'Yes'
                                  else 'No'
                             end
      
       From  cte
       Where RN=1
      

      结果

      ID  MemberName  StartOfMonth    Increase_Risk   Derease_Risk
      1   John Doe    2021-03-01      No              No
      1   John Doe    2021-05-01      Yes             No
      1   John Doe    2021-06-01      Yes             No
      2   Sam         2021-05-01      No              Yes
      

      【讨论】: