如何为每个 ID 创建长度等于 ID 长度的不同日期序列?

how to create different sequence of dates whose length equals to id length for each id?

提问人:AlSub 提问时间:7/29/2023 更新时间:8/1/2023 访问量:59

问:

我有一个表,每个 id 的长度不同,每个 id date_column值相同:

id     date_column
A      2020-05-20
A      2020-05-20
A      2020-05-20
B      2020-07-23    
B      2020-07-23
C      2021-08-27
C      2021-08-27

我想知道是否可以添加一个额外的生成列 按日期序列计算,其中每个开始日期值将是日期列上每个 ID 的唯一日期值,后续值将是起始值减去一个月,第二个值是起始值减去两个月,依此类推,直到出现新 ID 并出现新的开始日期值,并为其生成新序列。

预期输出应如下所示 -

id     date_column      generated_column    
A      2020-05-20        2020-05-20
A      2020-05-20        2020-04-20
A      2020-05-20        2020-03-20
B      2020-07-23        2020-07-23
B      2020-07-23        2020-06-23
C      2021-08-27        2021-08-27
C      2021-08-27        2021-07-27

可以通过在snowflake中使用sql来添加此列吗?

sql 日期 snowflake-cloud-data-platform 序列

评论

3赞 nbk 7/29/2023
将行号减去为月。从日期开始,作为分区,您可以使用 Id 和日期

答:

1赞 Kathmandude 7/29/2023 #1

正如@nbk在评论中回避的那样.....你可以做

select *, add_months(date_column, -1 * (row_number() over (partition by id order by date_column)-1)
from t;
2赞 Simeon Pilgrim 7/29/2023 #2

所以就像 nbk 说的,和 Radagast 注意,但以稍微更容易阅读的形式(恕我直言):

with fake_data(id, date_coumn) as (
    select * from values
        ('A', '2020-05-20'::date),
        ('A', '2020-05-20'::date),
        ('A', '2020-05-20'::date),
        ('B', '2020-07-23'::date),    
        ('B', '2020-07-23'::date),
        ('C', '2021-08-27'::date),
        ('C', '2021-08-27'::date)
)
select *
    ,row_number() over (partition by id order by null)-1 as rn
    ,dateadd('month', -rn, date_coumn) as gen_column
from fake_data
order by 1,gen_column desc;

给:

enter image description here

这显示了row_number如何为每个 ID 生成具有单独数字范围的值,以及如何没有值来对这些值进行排序,但您可以通过提供一个常量值来解决此问题,该值非常有效。 然后如何使用 dateadd 来“添加”负月份。null

根据 Radagast 的回答,这两行可以混合在一起,但这些行可能很难阅读/推理,因此另一种应该等同于相同执行的解决方法是将其保留为显式形式,并通过子选择执行列,如下所示:rn

select * exclude(rn) from (
    select *
        ,row_number() over (partition by id order by null)-1 as rn
        ,dateadd('month', -rn, date_coumn) as gen_column
    from fake_data
)
order by 1,gen_column desc;

给:

enter image description here