【问题标题】:Counting if 4 or more visits happen within 45 days of each other计算 45 天内是否有 4 次或更多访问
【发布时间】:2015-03-27 21:22:34
【问题描述】:

这里是示例数据。我只需要留住一个病人,如果他们在 45 天内有 4 次或更多次就诊。我已经转置了数据集并使用数组来找出一种方法,但我希望有一种更有效的方法。

Pat_ID  Date        Prov_ID
    A       05/12/2012  X1
    A       05/12/2012  X2
    B       11/12/2012  X1
    B       11/20/2012  X1
    B       01/12/2013  X1
    B       03/22/2013  X1
    C       04/25/2013  X1
    C       04/25/2013  X2
    C       04/27/2013  X1
    C       05/12/2013  X1
    C       05/22/2013  X2
    C       04/25/2012  X3
    ...

我从删除少于 4 个事件的观察开始。

任何想法都将不胜感激。

最终结果应该是一个只有 PAT_ID 且在 45 天内访问过 4 次或更多的数据集。

【问题讨论】:

  • 日期完全相同的 2 行算作 2 次访问还是 1 次访问?
  • 您更喜欢哪种类型的解决方案,SAS 还是 SQL?

标签: sql loops sas


【解决方案1】:

这是一个基于 SAS(而不是 SQL)的解决方案,使用 lag 函数。它只读取一次数据,因此应该非常高效,尤其是与自连接式解决方案相比。

首先按 ID 和访问日期对数据进行排序(如果还没有的话)

proc sort data=YourData; 
    by Pat_ID Date;
run;

如果您从 3 条记录中跟踪 Pat_ID 和日期,您可以测试它在 45 天内并且是同一位患者。如果是这样 - 将其添加到列表中。

data list_of_membs(keep=PAT_ID);
    set YourData;
    retain last_Pat_ID;*The last PAT_ID that was added to the list;

    pat_id_3back = lag3(Pat_ID); *PAT_ID from 3 records back;
    date_3back = lag3(date);

    If  pat_id = pat_id_3back 
        AND (date - date_3back) < 45 
        AND (PAT_ID != last_Pat_ID) THEN DO;
            output;
            last_PAT_ID = PAT_ID;
    END;
run;

【讨论】:

  • 这个答案完美回答了最初的问题,哪些患者在 45 天内就诊?但这个答案没有解决相关问题:哪些患者就诊时间在 45 天内?有多少人?这些访问集群是什么时候出现的?这些似乎是很自然的问题。
【解决方案2】:

这个也可以:

    proc sql;
     create table want as 
     select a.Pat_ID, a.Date, a.Prov_ID from YourData as a
     left join  YourData as b
     on
      (
       a.pat_id = b.pat_id
       and  intck('day',b.date,a.date)>=45
      )
     join 
     (select pat_id, count(*) from YourData
      group by pat_id
      having count(*)>4
     ) as c
     on
     (
       a.pat_id = c.pat_id
     )
     where b.date is not missing;
   quit;

【讨论】:

    【解决方案3】:

    我认为您应该能够通过自行加入结果并计算同一患者在所述行日期的 45 天内出现的次数来完成此操作。

    以下代码未经测试,但希望能让您朝着正确的方向前进。

    WITH X AS (
    --your original query here
    )
    
    SELECT
    X.*,
    COUNT(Y.Date) over (PARTITION BY X.Pat_ID, X.VisitID) as [# of visits within 45 days after this one]
    INTO #Y
    FROM X
    INNER JOIN X as Y on X.Pat_ID = Y.Pat_ID and Y.Date > X.Date and Y.Date < DATEADD(d,45,X.Date)
    
    SELECT DISTINCT
    *
    FROM #Y
    WHERE [# of visits within 45 days after this one] >= 3
    
    DROP TABLE #Y
    

    【讨论】:

    • 仅供参考 - SQL Server 2012 中的错误:Msg 4108, Level 15, State 1, Line 60 Windowed functions can only appear in the SELECT or ORDER BY clauses.
    • @BrennanPope SAS 实施了 ANSI 制定的大部分指南,但不是全部。它还允许 Data Step 选项,这可以解释为什么您认为此代码会产生错误。
    • 不管这个错误是否可能发生或应该发生,它确实发生了。此错误消息是从连接到运行 SQL Server 2012 的服务器的 SSMS 中的消息选项卡复制的。
    • 很好,我将更新我的答案以使用临时表。
    【解决方案4】:

    编辑:当我第一次回答这个问题时,我假设结果应该是原始表中彼此相隔 45 天内的记录。我现在已经包含了 Tim Sand 答案的 SQL Server 实现(一个没有自连接的),以防将来有人需要 SQL Server 版本。我认为值得说明的是,如果表中需要除 pat_id 之外的任何数据,则需要加入表中才能获取它。

    DECLARE @PatientVisits TABLE
    (
        VisitID INT PRIMARY KEY IDENTITY
        ,Pat_ID  VARCHAR(5)
        ,Date   DATETIME2
        ,Prov_ID VARCHAR(5)
    )
    
    INSERT INTO @PatientVisits
    VALUES
    
        ('A'       ,'05/12/2012'  ,'X1')
       ,('A'       ,'05/12/2012'  ,'X2')
       ,('B'       ,'11/12/2012'  ,'X1')
       ,('B'       ,'11/20/2012'  ,'X1')
       ,('B'       ,'01/12/2013'  ,'X1')
       ,('B'       ,'03/22/2013'  ,'X1')
       ,('C'       ,'04/25/2013'  ,'X1')
       ,('C'       ,'04/25/2013'  ,'X2')
       ,('C'       ,'04/27/2013'  ,'X1')
       ,('C'       ,'05/12/2013'  ,'X1')
       ,('C'       ,'05/22/2013'  ,'X2')
       ,('C'       ,'04/25/2012'  ,'X3');
    
    SELECT DISTINCT
        Pat_ID
    FROM
    (
        SELECT
            Pat_ID
            ,Date AS CurrentDate
            ,LAG (Date,3,'00:00') OVER ( PARTITION BY Pat_ID ORDER BY Date ASC ) AS DateThreeVisitsAgo
        FROM @PatientVisits
    ) Visits
    WHERE 
        DATEDIFF(DAY,DateThreeVisitsAgo,CurrentDate) <= 45 
    

    这是我原来的答案:

    DECLARE @PatientVisits TABLE
    (
        VisitID INT PRIMARY KEY IDENTITY
        ,Pat_ID  VARCHAR(5)
        ,Date   DATETIME2
        ,Prov_ID VARCHAR(5)
    )
    
    INSERT INTO @PatientVisits
    VALUES
    
        ('A'       ,'05/12/2012'  ,'X1')
       ,('A'       ,'05/12/2012'  ,'X2')
       ,('B'       ,'11/12/2012'  ,'X1')
       ,('B'       ,'11/20/2012'  ,'X1')
       ,('B'       ,'01/12/2013'  ,'X1')
       ,('B'       ,'03/22/2013'  ,'X1')
       ,('C'       ,'04/25/2013'  ,'X1')
       ,('C'       ,'04/25/2013'  ,'X2')
       ,('C'       ,'04/27/2013'  ,'X1')
       ,('C'       ,'05/12/2013'  ,'X1')
       ,('C'       ,'05/22/2013'  ,'X2')
       ,('C'       ,'04/25/2012'  ,'X3');
    
    SELECT 
        VisitID
        ,Pat_ID
        ,Date
        ,Prov_ID
    FROM
    (
        SELECT
            P.VisitID
            ,P.Pat_ID
            ,P.Date
            ,P.Prov_ID
            ,COUNT(*) OVER (PARTITION BY P.VisitID) AS NearVisitCount
        FROM @PatientVisits P
        JOIN @PatientVisits P2
            ON P.Pat_ID = P2.Pat_ID
            AND P.Date BETWEEN DATEADD(DAY,-45,P2.Date) AND DATEADD(DAY,45,P2.Date)
    
    ) Visits
    WHERE
        NearVisitCount >= 4 
    GROUP BY 
        VisitID
        ,Pat_ID
        ,Date
        ,Prov_ID
    

    结果:

    VisitID Pat_ID  Date        Prov_ID
    7       C       2013-04-25  X1
    8       C       2013-04-25  X2
    9       C       2013-04-27  X1
    10      C       2013-05-12  X1
    11      C       2013-05-22  X2
    

    【讨论】:

    • 如果您真的想要,我很乐意提供一个不使用身份作为主键的示例。
    • 我想我认为输出中需要的不仅仅是患者 ID 的列表。回顾这个问题,似乎只需要一份患者 ID 的列表。为了后代,我将提供 Tim Sand 答案的 SQL 实现。
    猜你喜欢
    • 2021-12-10
    • 2013-03-08
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    • 2021-12-31
    相关资源
    最近更新 更多