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

Redshift递归CTE结合数组展开报错:set_cte_path无法找到CTE dates

Redshift递归CTE与数组展开结合报错:set_cte_path cannot find CTE dates

递归CTE dates 单独执行时完全正常,数组展开操作单独执行也无问题,但将二者结合在同一条查询中时,Amazon Redshift会抛出错误:ERROR: set_cte_path cannot find CTE dates。

报错的完整查询代码

with recursive
    start_dt as (select '2024-12-01'::date s_dt),
    end_dt as (select dateadd(day, 1, '2025-01-01'::date)::date e_dt),
    -- 递归CTE,声明列`dt`
    dates (dt) as (
        -- 起始日期
        select s_dt dt from start_dt
        union all
        -- 递归生成后续日期
        select dateadd(day, 1, dt)::date dt  -- 转换为date类型避免类型不匹配
        from dates
        where dt <= (select e_dt from end_dt)  -- 终止条件:到结束日期为止
),
all_dates as (
    select dt as range_date
    from dates
),
test_data as (
    select 'test1' as account_id, '2025-01-01' as date, array('123', '456') as ids_array
    union
    select 'test2' as account_id, '2025-01-01' as date, array('789', '101') as ids_array
),
test_data_with_dates as (
    select td.*
    from test_data td
    join all_dates d on d.range_date = td.date
)
select tdd.account_id, id from test_data_with_dates as tdd, tdd.ids_array as id

单独运行正常的场景

1. 仅递归CTE的查询

代码

with recursive
    start_dt as (select '2024-12-01'::date s_dt),
    end_dt as (select dateadd(day, 1, '2025-01-01'::date)::date e_dt),
    -- 递归CTE,声明列`dt`
    dates (dt) as (
        -- 起始日期
        select s_dt dt from start_dt
        union all
        -- 递归生成后续日期
        select dateadd(day, 1, dt)::date dt  -- 转换为date类型避免类型不匹配
        from dates
        where dt <= (select e_dt from end_dt)  -- 终止条件:到结束日期为止
),
all_dates as (
    select dt as range_date
    from dates
),
test_data as (
    select 'test1' as account_id, '2025-01-01' as date, array('123', '456') as ids_array
    union
    select 'test2' as account_id, '2025-01-01' as date, array('789', '101') as ids_array
),
test_data_with_dates as (
    select td.*
    from test_data td
    join all_dates d on d.range_date = td.date
)
select tdd.* from test_data_with_dates as tdd

查询结果

account_id,date,ids_array
test2,2025-01-01,["789","101"]
test1,2025-01-01,["123","456"]

2. 仅数组展开的查询

代码

with test_data as (
    select 'test1' as account_id, '2025-01-01' as date, array('123', '456') as ids_array
    union
    select 'test2' as account_id, '2025-01-01' as date, array('789', '101') as ids_array
),
test_data_with_dates as (
    select td.*
    from test_data td
)
select tdd.account_id, id from test_data_with_dates as tdd, tdd.ids_array as id

查询结果

account_id,id
test1,"123"
test1,"456"
test2,"789"
test2,"101"

解决方法

该问题大概率是Redshift解析器在处理递归CTE与隐式数组展开(逗号分隔语法)结合时的bug,可通过以下两种方式规避:

方式1:改用显式unnest函数

将隐式数组展开的语法替换为显式调用unnest函数,修改后的查询代码:

with recursive
    start_dt as (select '2024-12-01'::date s_dt),
    end_dt as (select dateadd(day, 1, '2025-01-01'::date)::date e_dt),
    dates (dt) as (
        select s_dt dt from start_dt
        union all
        select dateadd(day, 1, dt)::date dt
        from dates
        where dt <= (select e_dt from end_dt)
),
all_dates as (
    select dt as range_date
    from dates
),
test_data as (
    select 'test1' as account_id, '2025-01-01'::date as date, array('123', '456') as ids_array
    union
    select 'test2' as account_id, '2025-01-01'::date as date, array('789', '101') as ids_array
),
test_data_with_dates as (
    select td.*
    from test_data td
    join all_dates d on d.range_date = td.date
)
select tdd.account_id, unnest(tdd.ids_array) as id 
from test_data_with_dates as tdd

方式2:物化递归CTE结果

先将递归CTE生成的日期数据存入临时表,再进行后续的关联和数组展开操作:

-- 物化递归CTE结果到临时表
create temp table temp_dates as
with recursive
    start_dt as (select '2024-12-01'::date s_dt),
    end_dt as (select dateadd(day, 1, '2025-01-01'::date)::date e_dt),
    dates (dt) as (
        select s_dt dt from start_dt
        union all
        select dateadd(day, 1, dt)::date dt
        from dates
        where dt <= (select e_dt from end_dt)
    )
select dt as range_date from dates;

-- 执行后续查询
with test_data as (
    select 'test1' as account_id, '2025-01-01'::date as date, array('123', '456') as ids_array
    union
    select 'test2' as account_id, '2025-01-01'::date as date, array('789', '101') as ids_array
),
test_data_with_dates as (
    select td.*
    from test_data td
    join temp_dates d on d.range_date = td.date
)
select tdd.account_id, id from test_data_with_dates as tdd, tdd.ids_array as id;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 00:34:53