使用SQL在给定时间范围内查找事件

时间:2012-11-12 19:15:35

标签: sql sql-server tsql

我的大脑此刻必须完全糊涂,因为我坚持这一点。我有一张桌子上有一个日期,有人被给予了药物,这是他们服用药物的天数。一个人可以被处方n个药物,因此以下查询的CTE是找到最大的时间范围(药物的填写日期+天数供应。)然后我想找到那些人在至少七种不同的药物同时使用。我无法找到人们在给定时间内使用的药物。这需要限制在一个人同时服用至少seven药物的时间段内。一切正常,直到最后一部分。

来自CTE的样本数据(fillDate + longestscript = endingDate)

enter image description here

并发脚本由查询中的count(distinct rx.drugname)确定

enter image description here

  ;with cte 
as
(
      select rx.patid
        ,rx.fillDate
        ,MAX(rx.dayssup) as longestScript
        ,DATEADD(day,cast(rx.dayssup as int),rx.filldate) as endingDate
        from rx
        group by rx.patid, rx.fillDate,rx.daysSup
 ),
 startends as (
         select patid, FillDate as thedate, 1 as isstart 0 as isend
         from CTE union all
         select patid, EndingDate as thedate, 0 as isstart, 1 as isend
         from CTE
     ),
     cums as (
         select se.*,
                (select min(thedate) from startends se2 where se2.filledate > se.filldate) as nextdate,
                (select SUM(isstart) from startends se2 where se2.filldate <= se.filldate) as cumstarts,
                (select SUM(isend) from startends se2 where se2.filldate <= se.filldate) as cumends
         from startends se
     )
select *
from cums
where sumstarts - cumends >= 7

您可以在第二个查询中看到每个患者多次出现,fillDate和endingDate之间的时间跨度不同。如何编写查询以获得第二个屏幕截图第一行重复的九种药物? SQL Server 08 r2是我的dbms。

2 个答案:

答案 0 :(得分:2)

您是否正在使用SQL Server 2012?该解决方案在该数据库中很多更简单,因为Microsoft扩展了窗口函数以包含部分和。

这个想法是计算每个可能日期的累积填充和结束次数 - 无论是填写日期还是结束日期。然后差异是累积脚本的数量。以下提供了每个日期的信息:

with cte as (<your query>),
     startends as (
         select patid, FillDate as thedate, 1 as isstart 0 as isend
         from CTE union all
         select patid, EndingDate as thedate, 0 as isstart, 1 as isend
         from CTE
     ),
     cums as (
         select se.*,
                (select min(thedate) from startends se2 where se2.filledate > se.filldate) as nextdate,
                (select SUM(isstart) from startends se2 where se2.filldate <= se.filldate) as cumstarts,
                (select SUM(isend) from startends se2 where se2.filldate <= se.filldate) as cumends
         from startends se
     )
select *
from cums
where cumstarts - cumends >= 7

结果集中的每一行都有一个&#34; nextdate&#34;它定义了条件成立的时间段。您可能会在一段时间内获得多个记录,因为患者会从7到8到9到8到9到7个并发处方。

如果您有大量数据,这将是一个相当低效的查询,因为它正在进行相当昂贵的连接操作。但正如我所说,这在SQL Server 2012中会非常有效。

答案 1 :(得分:1)

我不太确定你的架构,所以我要稍微猜测一下,但我注意到的第一件事就是在你的CTE x中,你选择的是MAX(DaysSup),还要按{{1}进行分组,使最大冗余。

但是,我并不认为这与您的问题有关。我个人会采取不同的方法来解决这个问题。我假设你有一个表格:

dayssup

所以你可以按照以下方式做点什么:

CREATE TABLE rx
(       PatID           INT,
        FillDate        DATE,
        Dayssup         INT,
        DrugName        VARCHAR(50)
)

这将列出每位患者服用药物的所有日期,而不是范围,因此您可以使用以下内容:

SELECT  rx.PatID,
        rx.FillDate,
        rx.DrugName,
        [DateTaken] = DATEADD(DAY, v.Number, FillDate)
FROM    RX
        INNER JOIN master..spt_values v
            ON v.Number BETWEEN 0 AND rx.DaysSup
            AND v.Type = 'P'

我已经介绍的第一部分,第二部分简单地将结果限制在7种或更多种药物的所有日期。第三个CTE按连续日期对每个患者进行分组,最后一个CTE将每个患者的最小值和最大值分组。

如果您需要在每个日期获取药物清单,您可以加入cte WITH x AS ( SELECT rx.PatID, rx.FillDate, rx.DrugName, [DateTaken] = DATEADD(DAY, v.Number, FillDate) FROM rx INNER JOIN master..spt_values v ON v.Number BETWEEN 0 AND rx.DaysSup AND v.Type = 'P' ), y AS ( SELECT x.PatID, x.DateTaken, DrugsTaken = COUNT(DISTINCT x.DrugName) FROM x GROUP BY x.PatID, x.DateTaken HAVING COUNT(DISTINCT x.DrugName) >= 7 ), z AS ( SELECT *, GroupID = DATEDIFF(DAY, - ROW_NUMBER() OVER(PARTITION BY PatID ORDER BY DateTaken DESC), DateTaken) FROM y ) SELECT z.PatID, [MostConccurent] = MAX(z.DrugsTaken), [DateStarted] = MIN(z.DateTaken), [DateEnded] = MAX(z.DateTaken) FROM z GROUP BY z.PatID, z.GroupID;

x