PostgreSQL 13.2:存储过程中调用游标执行FETCH的报错解决
PostgreSQL存储过程内部执行FETCH语句报错的解决方法
问题背景
现有存储过程procedure1定义如下:
CREATE OR REPLACE PROCEDURE procedure1 (p_cursor INOUT refcursor) AS $$ BEGIN OPEN p_cursor FOR SELECT emp_name FROM employee WHERE exchange_code = 'CSE' AND TIMESTAMP = (SELECT MAX (TIMESTAMP) FROM employee WHERE exchange_code = 'CSE'); DELETE FROM employee WHERE exchange_code = 'CSE'; END; $$ Language plpgsql;
单独执行CALL procedure1('curs');后再执行FETCH ALL FROM curs;可正常获取数据,但创建procedure2尝试在内部顺序执行这两个操作时出现语法错误:
CREATE OR REPLACE PROCEDURE procedure2() AS $$ DECLARE curs refcursor := 'curs'; BEGIN CALL procedure1('curs'); FETCH ALL FROM curs; END; $$ Language plpgsql;
报错信息:
ERROR: syntax error at or near ";"
LINE 7: FETCH ALL FROM curs;
^
SQL state: 42601
Character: 180
使用PostgreSQL 13.2版本,需解决该问题。
错误原因
在PL/pgSQL中,FETCH属于SQL命令,但不能直接在BEGIN块中裸写执行。PL/pgSQL对SQL语句的执行有特定要求:要么用PERFORM执行无需返回结果的SQL,要么将结果存储到变量中处理。
解决方法
方法一:用PERFORM执行FETCH(仅需消耗游标数据)
如果只是需要执行FETCH来处理游标(无需保留结果),可以用PERFORM包裹语句:
CREATE OR REPLACE PROCEDURE procedure2() AS $$ DECLARE curs refcursor := 'curs'; BEGIN CALL procedure1(curs); -- 建议用声明的变量替代硬编码字符串 PERFORM FETCH ALL FROM curs; END; $$ Language plpgsql;
方法二:将FETCH结果存入变量(需处理返回数据)
如果需要处理游标返回的emp_name,要定义变量接收结果,比如通过循环遍历游标:
CREATE OR REPLACE PROCEDURE procedure2() AS $$ DECLARE curs refcursor := 'curs'; v_emp_name employee.emp_name%TYPE; BEGIN CALL procedure1(curs); -- 循环遍历游标获取数据 LOOP FETCH curs INTO v_emp_name; EXIT WHEN NOT FOUND; -- 这里可添加对v_emp_name的处理逻辑,比如打印或写入其他表 RAISE NOTICE '员工姓名: %', v_emp_name; END LOOP; -- 可手动关闭游标(事务结束时也会自动关闭) CLOSE curs; END; $$ Language plpgsql;
补充说明
调用procedure1时,建议使用声明的curs变量而非硬编码的'curs',更符合PL/pgSQL的变量使用规范。
内容的提问来源于stack exchange,提问作者JavaLearner
相关产品推荐
相关产品推荐

