如果满足涉及所有行的条件,如何将多行汇总为一行
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
我有一个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 |