PostgreSQL存储过程调用报错:cursor 'bal_upd1'不存在
PostgreSQL存储过程游标报错:cursor "bal_upd1" does not exist
问题重现
我创建了一个存储过程,尝试用游标更新数据,但调用时出现错误。存储过程代码如下:
create or REPLACE PROCEDURE bal_upd(p_id int) as $$ DECLARE rc record; ----- cursor bal_upd1 CURSOR (p_id int) for select * from tbal where custid = p_id; begin open bal_upd1 (p_id); loop FETCH bal_upd1 into rc; exit when not found; update t_trans set balance = balance + rc.trans; COMMIT; end loop; close bal_upd1; end; $$ LANGUAGE plpgsql;
调用语句:
call bal_upd(1)
报错信息:
ERROR: cursor "bal_upd1" does not exist
CONTEXT: PL/pgSQL function bal_upd(integer) line 12 at FETCH
SQL state: 34000
错误原因
核心问题是游标参数名与存储过程入参名冲突:游标定义里的p_id int和存储过程的入参p_id int完全同名,导致PL/pgSQL解析时混淆了两者的作用域,游标无法被正确初始化打开,最终FETCH时提示游标不存在。
另外,循环内每次更新后立即执行COMMIT的做法不合理:会频繁创建事务,增加数据库日志开销,且若循环中途出错,已提交的更新无法回滚,可能造成数据不一致。
修正后的代码
create or REPLACE PROCEDURE bal_upd(p_cust_id int) as $$ DECLARE rc record; -- 修改游标参数名,避免与存储过程入参冲突 bal_upd1 CURSOR (cursor_cust_id int) for select * from tbal where custid = cursor_cust_id; begin open bal_upd1 (p_cust_id); loop FETCH bal_upd1 into rc; exit when not found; update t_trans set balance = balance + rc.trans; end loop; -- 统一在循环结束后提交事务 COMMIT; close bal_upd1; end; $$ LANGUAGE plpgsql;
关键说明
- 解决参数冲突:只需保证游标参数名和存储过程入参名不同即可,这里将存储过程入参改为
p_cust_id,游标参数改为cursor_cust_id,让PL/pgSQL能正确区分两者的作用域,游标即可正常打开和使用。 - 事务优化:将
COMMIT移至循环外部,所有更新完成后一次性提交事务,既提升执行效率,也保证了事务的原子性——若循环中任意步骤出错,所有更新都会回滚,避免数据不一致。
内容的提问来源于stack exchange,提问作者raman
相关产品推荐
相关产品推荐

