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
相关产品推荐
相关产品推荐

