【问题标题】:Category sequence of events by date T-SQL按日期分类的事件序列 T-SQL
【发布时间】:2017-08-11 14:19:39
【问题描述】:

考虑为高血压补充处方药。有多种药物会影响血压,有些患者对某些药物的反应比其他药物更好,因此需要对每种药物进行短期试验以找到合适的药物。我希望能够识别每次处方试验以及每次试验的时间。如果患者按顺序尝试药物 A、药物 B、药物 A,则每次试验都需要一个唯一的 ID。我的问题是为第二个药物 A 试验分配一个唯一的 ID。不知道如何将它与第一个试验区分开来。

患者药物填充日期 DaySupply ABC A 2017 年 1 月 1 日 30 ABC A 17 年 2 月 1 日 30 ABC B 2017 年 3 月 1 日 30 ABC A 2017 年 4 月 1 日 30 我想要一个类似的结果: 患者药物填充日期日期供应顺序 ABC A 2017 年 1 月 1 日 30 1 ABC A 17 年 2 月 1 日 30 1 ABC B 17 年 3 月 1 日 30 2 ABC A 17 年 4 月 1 日 30 3

【问题讨论】:

  • 请标记您正在使用的数据库。

标签: sql sql-server tsql


【解决方案1】:

使用lag 将前一行的药物值与当前行的值进行比较。如果它们不相等,请使用 case 表达式来重置组开始指示符。然后使用运行总和来分配连续的组号。

select patient,drug,filldate,daysupply
,sum(col) over(partition by patient order by filldate) as sequence
from (select t.*,
      case when lag(drug) over(partition by patient order by filldate) = drug then 0 else 1 end as col
      from tbl t
     ) t

这假设您使用的 SQL Server 版本支持 lagsum 窗口函数。

【讨论】:

  • 这行得通,但我不明白 sum 函数是如何按药物试验划分的。因此,如果患者进行了 3 次试验,我希望“sum(col) over(partition by patient order by filldate) as sequence”为该患者的序列列中的每一行产生一个 3。基本上只是对那个病人的整个列求和。可能我并没有想象中那么理解窗口函数!
【解决方案2】:

MSSQL 的示例代码如下:

CREATE TABLE #patientInfo ( Patient VARCHAR(10), Drug varchar(10)  ,FillDate date , DaySupply int)

INSERT INTO #patientInfo
VALUES ('abc','a','20170101',30),('abc','a','20170102',30),('abc','b','20170103',30)

SELECT Patient, Drug, FillDate, DaySupply , ROW_NUMBER() over(partition by Patient,Drug ORDER BY Filldate) as Seq
from #patientInfo

【讨论】:

    【解决方案3】:

    首先,如果您要工作几天,您应该考虑使用Calendar Table。它简化了事情。

    create table Calendar
    (
        id int primary key identity,
        date datetime not null
    
        --various computed date attributes that we elide for now...
    )
    
    --populate with few years worth of days:
    
    declare @dt datetime
    set @dt = '1/1/2017'
    
    while @dt <= '12/31/2020'
    begin
    
        insert Calendar select @dt
    
        set @dt = dateadd(day, 1, @dt)
    
    end
    

    因此,您的架构可能看起来像这样:

    create table Drug
    (
        id int primary key identity,
        name nvarchar(100) not null
    )
    
    create table Patient
    (
        id int primary key identity,
        name nvarchar(100) not null
    )
    
    create table DrugTrial
    (
        patient int foreign key references Patient,
        drug int foreign key references Drug,
        date int foreign key references Calendar,
        supply int
    )
    

    关于此架构,您的示例数据是:

    insert Patient select 'ABC'
    
    insert Drug select 'A'
                union select 'B'
    
    insert DrugTrial 
        select 1, 1, 1, 30 union
        select 1, 1, 31, 30 union
        select 1, 2, 61, 30 union
        select 1, 1, 91, 30
    

    我们可以通过单个常规查询获得所需的结果集,但为了清楚起见,我们将使用一系列公用表表达式。

    首先,我们生成具有前驱的所有试验的集合。这意味着我们希望在使用相同药物和患者的试验之后立即进行所有试验:

    with Q as
    (
        select T.* from DrugTrial S
            cross apply
            (
                select * from DrugTrial T 
                   where T.date = S.date + S.supply and 
                         T.patient = S.patient and T.drug = S.drug
            ) T         
    ),
    

    接下来,我们需要计算位于序列开头的试验集。但这很容易,因为它只是所有试验的集合减去具有前驱的试验子集(如上面在 Q 中定义的)。

    P as
    (
        select patient, drug, date, supply from DrugTrial 
                  except select patient, drug, date, supply from Q
    ),
    

    最后,我们使用递归查询来构建序列:

    R as
    (
        select *, row_number() over (order by date) as seq from P
            union all
                select Q.*, S.seq from Q cross apply
                    (select * from R 
                       where Q.date = R.date + R.supply 
                           and Q.patient = R.patient and R.drug = Q.drug) S
    
    )
    

    R 的基本情况只是集合P,我们使用row_number 函数对其进行扩充以生成我们的序列号。 R 的递归情况只是为 R 中的每个试验计算后继试验(如果有)。

    把它们放在一起:

    select 
    
       Pt.id patient_id, Pt.name patient_name, 
       D.id drug_id, D.name drug_name, 
       R.supply, R.date, R.seq 
    
    from R inner join Patient Pt on Pt.id = R.patient 
           inner join Drug D on D.id = R.drug 
           inner join Calendar C on C.id = R.date order by R.date
    

    产生结果:

    patient_id  patient_name     drug_id     drug_name     supply      date   seq
    ----------- ---------------- ----------- ------------- ----------- ------ ---
    1           ABC              1           A             30          1      1
    1           ABC              1           A             30          31     1
    1           ABC              2           B             30          61     2
    1           ABC              1           A             30          91     3
    

    您可以看到整个解决方案here。它被封装在一个未提交的事务中,以便于使用。

    【讨论】:

      猜你喜欢
      • 2013-01-07
      • 1970-01-01
      • 1970-01-01
      • 2019-12-31
      • 2010-10-17
      • 2020-11-19
      • 2017-07-12
      • 1970-01-01
      • 2017-06-03
      相关资源
      最近更新 更多