我正在调整一些PL / pgSQL代码,因此我的refcursor
可以将表名作为参数。因此我更改了以下行:
declare
pointCurs CURSOR FOR SELECT * from tableName for update;
这一个:
OPEN pointCurs FOR execute 'SELECT * FROM ' || quote_ident(tableName) for update;
我调整了循环,然后,循环经历了。现在在循环中的某个时刻我需要更新记录(由光标指向)并且我卡住了。我该如何正确调整以下代码行?
UPDATE tableName set tp_id = pos where current of pointCurs;
我修复了tableName
和pos
的引号,并在开头添加了EXECUTE
子句,但我在where current of pointCurs
上收到了错误。
(i)如何更新记录?
(ii)该函数适用于公共模式中的表,而来自其他模式的表(例如trace.myname)失败。
任何评论都非常感谢..
答案 0 :(得分:15)
EXECUTE
不是“子句”,而是执行SQL字符串的PL / pgSQL命令。游标在命令中不可见。您需要将值传递给它。
因此,您无法使用特殊语法WHERE CURRENT OF
cursor
。我使用系统列ctid
来确定行而不知道唯一列的名称。请注意,ctid
仅保证在同一事务中保持稳定。
CREATE OR REPLACE FUNCTION f_curs1(_tbl text)
RETURNS void AS
$func$
DECLARE
_curs refcursor;
rec record;
BEGIN
OPEN _curs FOR EXECUTE 'SELECT * FROM ' || quote_ident(_tbl) FOR UPDATE;
LOOP
FETCH NEXT FROM _curs INTO rec;
EXIT WHEN rec IS NULL;
RAISE NOTICE '%', rec.tbl_id;
EXECUTE format('UPDATE %I SET tbl_id = tbl_id + 10 WHERE ctid = $1', _tbl)
USING rec.ctid;
END LOOP;
END
$func$ LANGUAGE plpgsql;
还有FOR
statement to loop through cursors的变体,但它仅适用于绑定游标。我们必须在这里使用未绑定的游标。
FOR
循环对于plpgsql中的显式游标,通常不需要。请改用FOR
循环的隐式光标:
CREATE OR REPLACE FUNCTION f_curs2(_tbl text)
RETURNS void AS
$func$
DECLARE
_ctid tid;
BEGIN
FOR _ctid IN EXECUTE 'SELECT ctid FROM ' || quote_ident(_tbl) FOR UPDATE
LOOP
EXECUTE format('UPDATE %I SET tbl_id = tbl_id + 100 WHERE ctid = $1', _tbl)
USING _ctid;
END LOOP;
END
$func$ LANGUAGE plpgsql;
或者更好,但是(如果可能!):在基于集合的操作方面重新思考您的问题并执行单个(动态)SQL命令:
-- Set-base dynamic SQL
CREATE OR REPLACE FUNCTION f_nocurs(_tbl text)
RETURNS void AS
$func$
BEGIN
EXECUTE format('UPDATE %I SET tbl_id = tbl_id + 1000', _tbl);
-- add WHERE clause as needed
END
$func$ LANGUAGE plpgsql;
SQL Fiddle展示了所有3种变种。
trace.myname
等模式限定的表名实际上包含两个标识符。你必须
regclass
类型:CREATE OR REPLACE FUNCTION f_nocurs(_tbl regclass)
RETURNS void AS
$func$
BEGIN
EXECUTE format('UPDATE %s SET tbl_id = tbl_id + 1000', _tbl);
END
$func$ LANGUAGE plpgsql;
我从%I
切换到%s
,因为regclass
参数会在(自动)转换为text
时自动正确转义。
这个相关答案的更多细节: