sql - 如何识别特定时间范围内发生的行?

标签 sql sql-server common-table-expression overlap

我有一张表,其中包含患者的医院就诊情况。我正在尝试标记上次访问后 90 天内发生的访问。然而,需要注意的是,一旦一次访问被标记为重叠访问,该访问就不应用于评估与另一次访问的重叠。让我用一个例子来解释一下。

表格

visitID     patientid    visit_date  
1           23           1/12/2018
2           23           1/30/2018
3           23           4/20/2018
4           23           5/02/2018

在上面的示例中,患者就诊了 4 次。访问 2 是在访问 1 的 90 天内,因此访问 2 应标记为重叠。标记访问 2 后,该行不应用于分析任何 future 访问的重叠识别。从概念上讲,这就像删除访问 2 并重新开始分析。

中期阶段(访问 2 被删除,分析再次开始)

visitID     patientid    visit_date  
1           23           1/12/2018
3           23           4/20/2018
4           23           5/02/2018

因此,即使访问 3 与访问 2 重叠,由于访问 2 已从分析中删除,因此访问 3 不会被标记为前一次访问(访问 1)距离超过 90 天。最后,应标记第 4 次访问,因为它与未标记的访问重叠。

预期输出

visitID     patientid    visit_date flag
1           23           1/12/2018  0
2           23           1/30/2018  1
3           23           4/20/2018  0 
4           23           5/02/2018  1

我尝试解决这个难题:

WITH overlaps AS 
    (SELECT DISTINCT T2.visit
    FROM visits_table AS T1
    INNER JOIN visits_table AS T2
            ON T1.visit != T2.visit
                AND T2.visit_date BETWEEN T1.visit_date AND DATEADD(DAY, 89, T1.visit_date))
    
    SELECT T3.visit, T3.patientid, T3.visit_date,
    CASE WHEN EXISTS (SELECT 1 FROM overlaps
                        WHERE overlaps.visit = T3.visit) 
                THEN 1
                ELSE 0
                END flag
    FROM visits_table T3

我的代码正在做的是检查每一行,无论是否应该在分析中使用它。我不知道如何使其动态化,以便忽略应该忽略的行。

数据集:

create table visits_table (visit int,patientid int,visit_date date);

INSERT INTO visits_table (visit, patientid, visit_date) VALUES (1,23,'1/12/2018')
INSERT INTO visits_table (visit, patientid, visit_date) VALUES (2,23,'1/30/2018')
INSERT INTO visits_table (visit, patientid, visit_date) VALUES (3,23,'4/20/2018')
INSERT INTO visits_table (visit, patientid, visit_date) VALUES (4,23,'5/02/2018')

最佳答案

我相信你必须使用递归 CTE 来做到这一点:

with vt as (
      select vt.*, row_number() over (partition by patientid order by visit_date) as seqnum
      from visits_table vt
     ),
     cte as (
      select vt.visit, vt.patientid, vt.visit_date, vt.visit_date as first_visit_date, seqnum
      from vt
      where seqnum = 1
      union all
      select vt.visit, vt.patientid, vt.visit_date,
             (case when vt.visit_date > dateadd(day, 90, cte.first_visit_date) then vt.visit_date else cte.first_visit_date end),
             vt.seqnum
      from cte join
           vt
           on vt.seqnum = cte.seqnum + 1 and vt.patientid = cte.patientid
     )
select cte.visit, cte.patientid, cte.visit_date,
       (case when first_visit_date = visit_date then 0 else 1 end) as flag
from cte
order by cte.patientid, cte.visit_date;

Here是一个数据库<> fiddle 。

关于sql - 如何识别特定时间范围内发生的行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55929329/

相关文章:

sql - F# 将列表插入 SQL Server

jquery - Mysql 删除本地 var 部分工作的行

sql-server - T-SQL 层次结构查询

sql-server - 存储过程不返回行 - 需要一些调试技巧

c# - 多个 MDF 文件 VS 单个数据库(SQL Server)

sql-server - 允许的公共(public)表表达式 (CTE) 表达式的数量是否有限制?

mysql - MySql中树结构(邻接表)的递归CTE

mysql - 如何在没有for循环的情况下插入一批空行?

sql - 使用proc sql将多个不同结构的表堆叠到一张表中

SQL PIVOT 仅一列