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

PL/pgSQL存储过程FETCH时报错:cursor 'cur_input'不存在

PL/pgSQL存储过程FETCH时游标不存在问题排查

我是PL/pgSQL新手,编写了public.import_candles存储过程,调用该过程时在FETCH步骤出现错误:ERROR: cursor "cur_input" does not exist,无法理解原因,请求帮忙排查问题。

相关代码及错误信息

存储过程代码

CREATE OR REPLACE PROCEDURE public.import_candles(
    IN in_source varchar(16),
    IN in_timeframe varchar(3),
    IN in_symbol varchar(8),
    IN in_bulk integer DEFAULT 10000)
LANGUAGE 'plpgsql'
AS $BODY$
declare
    bulkCounter int;
    rec_input record;
    cur_input cursor(psource varchar(16), ptimeframe varchar(3), psymbol varchar(8)) for
        select distinct time, open, high, low, close, volume
        from candlesticks_input
        where source = psource and timeframe = ptimeframe and symbol = psymbol;
begin
    bulkCounter := 0;
    open cur_input(in_source, in_timeframe, in_symbol);
    
    loop
        fetch cur_input into rec_input;
        exit when not found;

        -- more code here ...
        
        bulkCounter = bulkCounter + 1;
        if MOD(bulkCounter,in_bulk) = 0 then
            commit;
        end if;
    
    end loop;
    
    close cur_input;
    commit;
end
$BODY$;

调用语句

call import_candles('MY_SOURCE', 'H1', 'EURUSD');

错误信息

ERROR:  cursor "cur_input" does not exist
CONTEXT:  PL/pgSQL function import_candles(character varying,character varying,character varying,integer) line 14 at FETCH
SQL state: 34000

问题原因

核心问题是显式游标在执行COMMIT后会被自动关闭。你在循环中每处理in_bulk条数据就执行一次commit,第一次commit后,cur_input游标就被关闭了,后续循环里的FETCH操作自然找不到这个游标,从而报错。

解决方案

方案1:改用隐式游标(推荐)

PL/pgSQL推荐使用隐式游标(FOR循环遍历查询结果),这种方式不需要手动管理游标打开/关闭,而且不受COMMIT操作影响。修改后的代码如下:

CREATE OR REPLACE PROCEDURE public.import_candles(
    IN in_source varchar(16),
    IN in_timeframe varchar(3),
    IN in_symbol varchar(8),
    IN in_bulk integer DEFAULT 10000)
LANGUAGE 'plpgsql'
AS $BODY$
declare
    bulkCounter int := 0;
begin
    for rec_input in 
        select distinct time, open, high, low, close, volume
        from candlesticks_input
        where source = in_source and timeframe = in_timeframe and symbol = in_symbol
    loop
        -- more code here ...
        
        bulkCounter := bulkCounter + 1;
        if MOD(bulkCounter, in_bulk) = 0 then
            commit;
        end if;
    end loop;
    
    commit;
end
$BODY$;

方案2:保留显式游标但避免中途COMMIT

如果必须使用显式游标,需要移除循环中的commit,只在最后执行一次commit。但这种方式会导致事务变大,可能影响性能或占用更多资源,适合数据量不大的场景。

方案3:使用WITH HOLD游标(不推荐频繁COMMIT场景)

可以将游标声明为WITH HOLD,这种游标在COMMIT后不会被关闭,但需要注意:

  • WITH HOLD游标只能在事务结束后继续存在,且需要手动关闭
  • 这种方式会增加数据库资源占用,不适合循环中频繁COMMIT的场景

修改游标声明部分:

cur_input cursor(psource varchar(16), ptimeframe varchar(3), psymbol varchar(8)) WITH HOLD for
    select distinct time, open, high, low, close, volume
    from candlesticks_input
    where source = psource and timeframe = ptimeframe and symbol = psymbol;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 07:15:34