【问题标题】:error while executing function with cursor使用光标执行函数时出错
【发布时间】:2025-12-28 08:25:17
【问题描述】:

我定义了一个函数如下

CREATE OR REPLACE FUNCTION processActivityCommentTable() RETURNS INTEGER AS $$
DECLARE
activityCommentRow RECORD;
i RECORD;
activityId integer;
attachments text;
attachmentId integer;
cur1 CURSOR FOR SELECT ac.id, ac.attachments from activitycomment ac where ac.attachments is not null;

BEGIN
OPEN cur1;
FOR activityCommentRow in cur1
    LOOP
    RAISE NOTICE 'currently processing for %s ...', activityCommentRow.id;
        -- can do some processing here
    activityId = activityCommentRow.id;
    attachments = activityCommentRow.attachments;

    SELECT foo FROM regexp_split_to_table(attachments,E'{"id":') as foo;

    FOR i in select * from foo
    LOOP
     select regexp_replace(i,'(,"name").*','') into attachmentId;
        EXECUTE 'INSERT INTO attachment (activity_comment_id) values(' || attachmentId ||') where id= ' activityId; 
    END LOOP;

    END LOOP;
CLOSE cur1;
END;

$$ LANGUAGE plpgsql;

在执行时

select processActivityCommentTable();

它给了我以下错误

错误:光标“cur1”已在使用中 SQL 状态:42P03 上下文:PL/pgSQL 函数 processactivitycommenttable() 第 12 行 FOR 光标上方

有人可以帮忙吗?

【问题讨论】:

    标签: postgresql postgresql-9.1 plpgsql


    【解决方案1】:

    简答:将查询放在 FOR 循环中,而不是光标。

    FOR 循环记录为:

    [标签]
    FOR 目标 IN 查询 LOOP
    声明
    结束循环[标签];

    query 被描述为:

    这种类型的 FOR 语句中使用的查询可以是任何 SQL 命令 将行返回给调用者:SELECT 是最常见的情况,但是 您还可以将 INSERT、UPDATE 或 DELETE 与 RETURNING 子句一起使用。 一些实用程序命令(例如 EXPLAIN)也可以使用。

    这并不意味着光标的名称可能存在。

    你可以给它一个针对游标而不是游标的 SQL 查询。

    如果确实需要游标,则从游标读取结果的命令是FETCH,因此可以接受这种形式:

    FOR activityCommentRow in FETCH ALL FROM cur1
    

    FETCH 的变体,例如如果只需要 3 行:

    FOR activityCommentRow in FETCH 3 FROM cur1
    

    【讨论】:

      【解决方案2】:

      当你使用FOR IN CURSOR 语句时,你不应该显式打开游标 -

      游标变量在声明时必须已绑定到某个查询,并且无法打开。 FOR 语句自动打开游标,循环退出时再次关闭游标。

      仅当您使用某种通用形式并通过语句FETCH 从游标读取数据时,才需要显式打开。详情在doc

      【讨论】: