在雪花视图中将日期范围拆分为新记录
Split date range into new records in Snowflake View
我有一个 table,它由开始日期和结束日期组成,我需要将记录拆分为按天计算的数据,这需要放在视图中。
| PersonID | CompanyID | Start_DT | End_DT |
|-----------|--------------|-------------|-----------|
| A12 | abc | 05-01-2020 | 05-03-2020|
| B23 | def | 06-08-2020 | 06-14-2020|
| PersonID | CompanyID | New_DT |
|-----------|--------------|-------------|
| A12 | abc | 05-01-2020 | ==> A12 Start Date is 05-01-2020 and End Date is 05-03-2020. So there are 3 records generated in New_DT
| A12 | abc | 05-02-2020 |
| A12 | abc | 05-03-2020 |
| B23 | def | 06-08-2020 |
| B23 | def | 06-09-2020 |
| B23 | def | 06-10-2020 |
| B23 | def | 06-11-2020 |
| B23 | def | 06-12-2020 |
| B23 | def | 06-13-2020 |
| B23 | def | 06-14-2020 |
如何在 View 中实现此目的?
您可以使用递归 CTE:
with cte as (
select PersonID, CompanyID, Start_DT as new_dt, End_DT
from t
union all
select PersonID, CompanyID, dateadd(day, 1, new_dt), End_DT
from cte
where new_dt < end_dt
)
select PersonID, CompanyID, new_dt
from cte
option (maxrecursion 0);
如果您的经期超过100天,那么您需要添加option (maxrecursion 0)
。
Here 是一个 db<>fiddle.
要填写日期,需要一种生成行的方法。一种已知快速有效的方法是 tally 或数字 table。像这样
Tally tvf(生成大量行,足以填充 BIGINT)
drop function if exists [dbo].[fnNumbers];
go
create function [dbo].[fnNumbers](
@zero_or_one bit,
@n bigint)
returns table with schemabinding as return
with n(n) as (select null from (values (1),(2),(3),(4)) n(n))
select 0 n where @zero_or_one = 0
union all
select top(@n) row_number() over(order by (select null)) n
from n na, n nb, n nc, n nd, n ne, n nf, n ng, n nh,
n ni, n nj, n nk, n nl, n nm, n np, n nq, n nr;
go
查询
select it.PersonID, it.CompanyID, da.dt
from #t it
cross apply
dbo.fnNumbers(0, datediff(day, Start_DT, End_DT)) fn
cross apply
(select dateadd(day, fn.n, it.Start_DT) dt) da;
输出
PersonID CompanyID dt
A12 abc 2020-05-01
A12 abc 2020-05-02
A12 abc 2020-05-03
B23 def 2020-06-08
B23 def 2020-06-09
B23 def 2020-06-10
B23 def 2020-06-11
B23 def 2020-06-12
B23 def 2020-06-13
B23 def 2020-06-14
我有一个 table,它由开始日期和结束日期组成,我需要将记录拆分为按天计算的数据,这需要放在视图中。
| PersonID | CompanyID | Start_DT | End_DT |
|-----------|--------------|-------------|-----------|
| A12 | abc | 05-01-2020 | 05-03-2020|
| B23 | def | 06-08-2020 | 06-14-2020|
| PersonID | CompanyID | New_DT |
|-----------|--------------|-------------|
| A12 | abc | 05-01-2020 | ==> A12 Start Date is 05-01-2020 and End Date is 05-03-2020. So there are 3 records generated in New_DT
| A12 | abc | 05-02-2020 |
| A12 | abc | 05-03-2020 |
| B23 | def | 06-08-2020 |
| B23 | def | 06-09-2020 |
| B23 | def | 06-10-2020 |
| B23 | def | 06-11-2020 |
| B23 | def | 06-12-2020 |
| B23 | def | 06-13-2020 |
| B23 | def | 06-14-2020 |
如何在 View 中实现此目的?
您可以使用递归 CTE:
with cte as (
select PersonID, CompanyID, Start_DT as new_dt, End_DT
from t
union all
select PersonID, CompanyID, dateadd(day, 1, new_dt), End_DT
from cte
where new_dt < end_dt
)
select PersonID, CompanyID, new_dt
from cte
option (maxrecursion 0);
如果您的经期超过100天,那么您需要添加option (maxrecursion 0)
。
Here 是一个 db<>fiddle.
要填写日期,需要一种生成行的方法。一种已知快速有效的方法是 tally 或数字 table。像这样
Tally tvf(生成大量行,足以填充 BIGINT)
drop function if exists [dbo].[fnNumbers];
go
create function [dbo].[fnNumbers](
@zero_or_one bit,
@n bigint)
returns table with schemabinding as return
with n(n) as (select null from (values (1),(2),(3),(4)) n(n))
select 0 n where @zero_or_one = 0
union all
select top(@n) row_number() over(order by (select null)) n
from n na, n nb, n nc, n nd, n ne, n nf, n ng, n nh,
n ni, n nj, n nk, n nl, n nm, n np, n nq, n nr;
go
查询
select it.PersonID, it.CompanyID, da.dt
from #t it
cross apply
dbo.fnNumbers(0, datediff(day, Start_DT, End_DT)) fn
cross apply
(select dateadd(day, fn.n, it.Start_DT) dt) da;
输出
PersonID CompanyID dt
A12 abc 2020-05-01
A12 abc 2020-05-02
A12 abc 2020-05-03
B23 def 2020-06-08
B23 def 2020-06-09
B23 def 2020-06-10
B23 def 2020-06-11
B23 def 2020-06-12
B23 def 2020-06-13
B23 def 2020-06-14