【问题标题】:SQL: Identify distinct blocks of treatment over multiple start and end date ranges for each memberSQL:识别每个成员在多个开始和结束日期范围内的不同处理块
【发布时间】:2014-06-02 17:16:00
【问题描述】:

目标:确定表中每个成员的不同连续治疗事件。每个成员都有一个诊断和一个服务日期,一个情节被定义为每个连续服务之间的时间小于某个数字的所有服务(假设本示例为 90 天)。查询将需要遍历每一行并计算日期之间的差异,并返回与每一集关联的第一个和最后一个日期。目标是按成员和剧集开始/结束日期对结果进行分组。

A very similar question 之前有人问过,而且有点帮助。问题是在自定义代码时,返回的表不包括第一条和最后一条记录。我不确定如何继续。

我的数据目前如下所示:

MemberCode       Diagnosis              ServiceDate         
1001   -----        ABC      -----       2010-02-04           
1001   -----        ABC      -----       2010-03-20          
1001   -----        ABC      -----       2010-04-18          
1001   -----        ABC      -----       2010-05-22         
1001   -----        ABC      -----       2010-09-26          
1001   -----        ABC      -----       2010-10-11  
1001   -----        ABC      -----       2010-10-19
2002   -----        XYZ      -----       2010-07-10          
2002   -----        XYZ      -----       2010-07-21
2002   -----        XYZ      -----       2010-11-08
2002   -----        ABC      -----       2010-06-03           
2002   -----        ABC      -----       2010-08-13         

以上数据中,Member 1001的第一条记录是2010-02-04,到2010-09-之前连续服务的时间相差不超过90天26(新剧集开始的日期)。所以会员 1001 有两个不同的情节:(1)诊断 ABC,从 2010-02-042010-05-22,以及(2)诊断 ABC,从 2010-09-262010-10-19

同样,Member 2002 有三个不同的情节:(1) 诊断 XYZ,从 2010-07-102010-07-21,(2)诊断 XYZ,从 2010-11-08 开始和结束,以及 (3) 诊断 ABC,从 2010-06-032010-08 -13.

期望的输出:

MemberCode         Diagnosis       EpisodeStartDate          EpisodeEndDate
1001   -----          ABC   -----     2010-02-04   -----       2010-05-22
1001   -----          ABC   -----     2010-09-26   -----       2010-10-19
2002   -----          XYZ   -----     2010-07-10   -----       2010-07-21
2002   -----          XYZ   -----     2010-11-08   -----       2010-11-08
2002   -----          ABC   -----     2010-06-03   -----       2010-08-13

我处理这个查询已经太久了,但仍然无法得到我真正需要的东西。任何帮助,将不胜感激。提前致谢!

【问题讨论】:

  • 你在 VA 工作吗?不过,说真的,我正在看。看看我能不能帮忙……
  • 您使用的是什么版本的 SQL Server?
  • 我使用的是 SQL Server 2012。

标签: sql sql-server tsql sequence gaps-and-islands


【解决方案1】:

SQL Server 2012 具有lag() 和累积求和函数,这使得编写这样的查询更加容易。这个想法是在每个序列中找到第一个。然后取第一个标志的累积和来识别每个组。代码如下:

select MemberId, Diagnosis, min(ServiceDate) as EpisodeStartDate,
       max(ServiceStartDate) as EpisodeEndDate
from (select t.*, sum(ServiceStartFlag) over (partition by MemberId, Diagnosis order by ServiceDate) as grp
      from (select t.*,
                   (case when datediff(day,
                                       lag(ServiceDate) over (partition by MemberId, Diagnosis
                                                              order by ServiceDate),
                                       ServiceDate) < 90
                         then 0
                         else 1 -- handles both NULL and >= 90
                    end) as ServiceStartFlag
            from table t
           ) t
group by grp, MemberId, Diagnosis;

您可以在早期版本的 SQL Server 中执行此操作,但代码比较麻烦。

【讨论】:

  • 这非常有效。我不知道 LAG() 功能,所以我很高兴知道这种功能的存在。非常感谢!
【解决方案2】:

对于 2012 之前的 SQL Server 版本,这里有一些应该可以工作的代码 sn-ps。 首先,您需要一个临时表(而不是 CTE,因为查找边缘事件将再次触发 newid() 函数,而不是检索该行的值)

DECLARE @Edges TABLE (MemberCode INT, Diagnosis VARCHAR(3), ServiceDate DATE, GroupID VARCHAR(40))

INSERT INTO @Edges
SELECT *
FROM Treatments E
    CROSS APPLY (
        SELECT 
            CASE
                WHEN EXISTS (
                    SELECT TOP 1 E2.ServiceDate
                    FROM Treatments E2
                    WHERE E.MemberCode = E2.MemberCode
                        AND E.Diagnosis = E2.Diagnosis
                        AND E.ServiceDate > E2.ServiceDate
                        AND DATEDIFF(dd,E2.ServiceDate,E.ServiceDate) BETWEEN 1 AND 90
                    ORDER BY E2.ServiceDate DESC
                    ) THEN 'Group'
                ELSE CAST(NEWID() AS VARCHAR(40))
            END AS GroupID
    ) z

EXISTS 运算符包含一个查询,该查询查看过去 1 到 90 天前的日期。收集完 Edge 案例后,此查询将根据您发布的测试数据提供您发布的结果。

SELECT MemberCode, Diagnosis, MIN(ServiceDate) AS StartDate, MAX(ServiceDate) AS EndDate
FROM (
    SELECT
          MemberCode
        , Diagnosis
        , ServiceDate
        , CASE GroupID
            WHEN 'Group' THEN (
                SELECT TOP 1 GroupID
                FROM @Edges E2
                WHERE E.MemberCode = E2.MemberCode
                    AND E.Diagnosis = E2.Diagnosis
                    AND E.ServiceDate > E2.ServiceDate
                    AND GroupID != 'Group'
                ORDER BY ServiceDate DESC
            )
            ELSE GroupID END AS GroupID
    FROM @Edges E
    ) Z
GROUP BY MemberCode, Diagnosis, GroupID
ORDER BY MemberCode, Diagnosis, MIN(ServiceDate)

就像 Gordon 说的那样,比较麻烦,但如果你的服务器不是 SQL 2012 或更高版本,也可以这样做。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    • 1970-01-01
    • 2019-02-25
    • 1970-01-01
    • 2019-07-06
    • 1970-01-01
    相关资源
    最近更新 更多