You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redshift SQL如何按起止日期拆分每行生成每日记录?

在Redshift中拆分日期范围为每日一行的解决方案

嘿,我来帮你搞定这个日期拆分的问题!你遇到的relation "cte" does not exist错误,其实是因为Redshift对递归CTE的语法有特定要求——你需要加上RECURSIVE关键字才能让递归逻辑生效。不过先别急,我会先帮你修复递归CTE的写法,再给你推荐一个更适合Redshift的高效方案。

一、修复你的递归CTE写法

Redshift基于PostgreSQL,递归CTE必须显式声明RECURSIVE,否则数据库会把递归部分当成普通的CTE引用,自然找不到名为cte的关系。修改后的代码如下:

WITH RECURSIVE cte AS (
    SELECT name, start_date, end_date 
    FROM dates
    UNION ALL
    SELECT name, DATEADD(day, 1, start_date), end_date 
    FROM cte 
    WHERE start_date < end_date
)
SELECT name, start_date AS date 
FROM cte
ORDER BY name, start_date;

这个代码可以正常运行,把你的示例数据拆分成每日一行:

  • Peter F. 会生成2018-03-01到2018-03-05的5行
  • Sam R. 会生成2018-04-17到2018-04-20的4行

不过要注意:递归CTE在Redshift里的性能很差,尤其是当你的表有大量行或者日期范围很长时,逐行递归的方式会拖慢查询速度,所以更推荐下面的方法。

二、更高效的数字序列关联法

Redshift更适合用预生成数字序列+关联查询的方式来拆分日期,这种方法是批量处理,性能比递归好很多。

方法1:利用系统表生成数字序列

Redshift的系统表(比如stl_scan)包含大量行,我们可以用它来生成连续的数字序列,覆盖你需要的最大日期范围:

-- 生成0到3650的数字(覆盖10年的日期,可按需调整LIMIT值)
WITH numbers AS (
    SELECT ROW_NUMBER() OVER () - 1 AS num
    FROM stl_scan
    LIMIT 3650
)
SELECT 
    d.name,
    DATEADD(day, n.num, d.start_date) AS date
FROM dates d
JOIN numbers n 
    ON DATEADD(day, n.num, d.start_date) <= d.end_date
ORDER BY d.name, date;

方法2:使用generate_series(适合较新版本Redshift)

如果你的Redshift版本支持generate_series(集群模式下现在也支持了),可以直接用它生成数字序列:

WITH numbers AS (
    SELECT generate_series(0, 3650) AS num
)
SELECT 
    d.name,
    DATEADD(day, n.num, d.start_date) AS date
FROM dates d
JOIN numbers n 
    ON DATEADD(day, n.num, d.start_date) <= d.end_date
ORDER BY d.name, date;

这两种方法的逻辑都是:生成从0开始的连续数字,每个数字对应start_date加上N天,只要结果不超过end_date,就保留这一行,最终得到每日的记录。

总结

  • 递归CTE适合小数据集快速测试,但性能不佳;
  • 数字序列关联法是Redshift的最优解,适合处理大规模数据。

内容的提问来源于stack exchange,提问作者Georgiy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:02:40