PostgreSQL使用WHERE CURRENT OF报错:游标不存在问题排查
问题描述
创建临时表AMB_LOMB:
CREATE TEMPORARY TABLE AMB_LOMB ( azienda_usl char(3), ospedale char(6) , numero_riga integer NOT NULL PRIMARY KEY, codice_associazione char(5), errore varchar(3), riferimento_errore varchar(10) , errore_grave integer , id_pai varchar(32) ) ON COMMIT PRESERVE ROWS ;
编写存储过程public.lomb_amb2019_SUBtest_0用于校验并更新该表:
CREATE OR REPLACE PROCEDURE public.lomb_amb2019_SUBtest_0() LANGUAGE 'plpgsql' AS $BODY$ declare zio record ; m_errore char(3); m_errore_grave integer; begin for zio in select azienda_usl as _azienda_usl, errore_grave , numero_riga as _numero_riga, errore from amb_lomb for update loop -- 执行一些计算和设置操作 m_errore_grave := '0' ; m_errore := ' ' ; update amb_lomb set errore_grave=m_errore_grave, errore=m_errore where current of zio ; end loop ; end; $BODY$;
执行call lomb_amb2019_SUBtest_0() ;时触发错误:
ERROR: 游标"zio"不存在 CONTEXT: SQL语句"update amb_lomb set errore_grave=m_errore_grave, errore=m_errore where current of zio" PL/pgSQL函数lomb_amb2019_subtest_0()第22行的SQL语句 ERRORE: 游标"zio"不存在 SQL state: 34000
但其他结构类似的存储过程操作同一张表却未报错,请问问题原因是什么?
问题原因及解决办法
核心原因
PostgreSQL的PL/pgSQL中,FOR ... IN SELECT这种隐式循环使用的是匿名隐式游标,而WHERE CURRENT OF语法仅支持显式声明的命名游标。你代码里的zio是循环迭代的record变量,并非游标对象,因此无法被WHERE CURRENT OF识别,导致报错“游标不存在”。
其他存储过程未报错的原因
那些存储过程大概率没有使用WHERE CURRENT OF,而是通过表的主键(如numero_riga)来定位更新行,或者显式声明了命名游标并正确使用。
修复方案
有两种常用修复方式:
通过主键字段更新(推荐):
利用表的主键numero_riga作为更新条件,直接用循环中获取的_numero_riga匹配:update amb_lomb set errore_grave=m_errore_grave, errore=m_errore where numero_riga = zio._numero_riga;显式声明命名游标:
先定义命名游标,再执行打开、循环、关闭操作,此时即可正常使用WHERE CURRENT OF:CREATE OR REPLACE PROCEDURE public.lomb_amb2019_SUBtest_0() LANGUAGE 'plpgsql' AS $BODY$ declare cur_zio cursor for select azienda_usl as _azienda_usl, errore_grave, numero_riga as _numero_riga, errore from amb_lomb for update; zio record; m_errore char(3); m_errore_grave integer; begin open cur_zio; loop fetch cur_zio into zio; exit when not found; m_errore_grave := '0' ; m_errore := ' ' ; update amb_lomb set errore_grave=m_errore_grave, errore=m_errore where current of cur_zio; end loop; close cur_zio; end; $BODY$;
内容的提问来源于stack exchange,提问作者Andrea Ricci
相关产品推荐
相关产品推荐

