如果满足涉及所有行的条件,如何将多行汇总为一行

How to roll up multiple rows into one if they meet a condition involving all the rows

我有一个table名字和访问数据如下

Name Visitlicensedate LicenseExpiredate
John 1/1/2020 3/30/2020
John 2/1/2020 5/2/2020
John 6/1/2020 9/30/2020
James 3/15/2020 6/14/2020

对于此处的每个名称,如果访问时间在 60 天内,我希望结果将 visitlicensedates 汇总为一个(第一个),并使用最后一个过期日期作为新的 licenseexpiredate。如果访问许可是在上次之后超过60天颁发的,我希望它开始一个新的记录所以结果如下:

Name Visitlicensedate LicenseExpiredate
John 1/1/2020 5/2/2020
John 6/1/2020 9/30/2020
James 3/15/2020 6/14/2020

我想不出解决办法。

您可以使用此存储过程获得预期结果:

create procedure my_custom_sp
as

create table #tbl (
    [name] varchar(20),
    [visitlicensedate] date,
    [licenseExpiredate] date
)

declare cur cursor for 

select [name], [visitlicensedate] from tbl

declare @name varchar(20), @visitlicensedate date

open cur
fetch next from cur into @name, @visitlicensedate

while @@FETCH_STATUS =0 
begin   
    
    insert into #tbl ([name], [visitlicensedate], [licenseExpiredate])
    select [name], min([visitlicensedate]), max([licenseExpiredate])    
    from tbl t1 where [name] = @name 
    and [visitlicensedate] < DATEADD(d,60,@visitlicensedate)
    and not exists (
        select * from #tbl t2 where [name] = @name 
        and DATEDIFF(d,t2.[visitlicensedate],t1.[visitlicensedate]) < 60 
    )
    group by [name]
            
    fetch next from cur into @name, @visitlicensedate
end
close cur
deallocate cur

select * from #tbl

go

结果

exec my_custom_sp

/*
name    visitlicensedate    licenseExpiredate
John    2020-01-01          2020-05-02
John    2020-06-01          2020-09-30
James   2020-03-15          2020-06-14
*/

或者,您可以使用间隙和孤岛方法将数据分组并按组执行计算。

WITH table1 AS (
SELECT *,
   ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Visitlicensedate) AS rownum,
   LAG(Visitlicensedate) OVER (PARTITION BY Name ORDER BY Visitlicensedate) AS nextvisit,
   MIN(Visitlicensedate) OVER (PARTITION BY Name ORDER BY Name) AS sortdate
FROM mytable
),
table2 AS (
SELECT *,
   DATEDIFF(day, nextvisit, Visitlicensedate) AS gap
FROM table1
),
table3 AS (
SELECT *,
   SUM(CASE WHEN gap < 60 THEN 0 ELSE 1 END ) OVER (PARTITION BY Name ORDER BY rownum) AS grp
FROM table2
),
table4 AS (
SELECT Name, MIN(sortdate) AS sortdate, MIN(Visitlicensedate) AS Visitlicense_Date,
   MAX(LicenseExpiredate) AS LicenseExpire_Date
FROM table3
GROUP BY Name, grp
)
SELECT Name, Visitlicense_Date, LicenseExpire_Date
FROM table4
ORDER BY sortdate;

Demo

结果

Name Visitlicense_Date LicenseExpire_Date
John 2020-01-01 2020-05-02
John 2020-06-01 2020-09-30
James 2020-03-15 2020-06-14