pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
和一次执行整个查询不同,可以建立一个 游标来封装该查询,并且接着一次读取该查询 结果的一些行。这样做的原因之一是在结果中包含大量行时避免内存 不足(不过,PL/pgSQL 用户通常不需要 担心这些,因为 FOR 循环在内部会自动使用一个 游标来避免内存问题)。一种更有趣的用法是返回一个函数已经创建 的游标的引用,允许调用者读取行。这提供了一种有效的方法从函数 中返回大型行集。
所有在 PL/pgSQL 中对游标的访问都会 通过游标变量,它总是特殊的数据类型 refcursor。创建游标变量的一种方法是把它声明为一个 类型为 refcursor 的变量。另外一种方法是使用游标声明 语法,通常是:
nameCURSOR [ (arguments) ] FORquery;
(为了兼容 Oracle,FOR 也可以写成 IS。) arguments 如果指定,它就是一个由 对组成的逗号分隔列表,这些名字会在给定查询中被参数值替换。实际 替换这些名字的值会在打开游标时提供。name datatype
Some examples:
DECLARE
curs1 refcursor;
curs2 CURSOR FOR SELECT * FROM tenk1;
curs3 CURSOR (key integer) IS SELECT * FROM tenk1 WHERE unique1 = key;
所有这三个变量都是 refcursor 类型,但是第一个可以 用于任何查询,而第二个已经被绑定了一个 完全指定的查询,并且最后一个被绑定了一个参数化查询。(游标被 打开时,key 将被一个整数参数值替换。)变量 curs1 被称为 未绑定,因为它没有被绑定到任何特定查询。
在能够使用游标检索行之前,必须先将其 打开(这等效于 SQL 命令 DECLARE CURSOR)。PL/pgSQL 有三种形式的 OPEN 命令,其中两种用于未绑定 游标变量,另一种用于已绑定游标变量。
OPEN FOR SELECT
OPEN unbound_cursor FOR SELECT ...;
该游标变量会被打开,并被赋予要执行的指定查询。该游标不能 已经处于打开状态,并且它必须已被声明为未绑定游标变量(即, 一个简单的 refcursor 变量)。SELECT 查询的处理方式与 PL/pgSQL 中的其他 SELECT 语句相同:替换 PL/pgSQL 变量名,并缓存查询计划 以备后续重用。
一个示例:
OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
OPEN FOR EXECUTEOPENunbound_cursorFOR EXECUTEquery_string;
该游标变量会被打开,并被赋予要执行的指定查询。该游标不能 已经处于打开状态,并且必须已被声明为未绑定游标变量(即, 一个简单的 refcursor 变量)。该查询以字符串 表达式的形式给出,这一点与 EXECUTE 命令相同。像往常一样,这提供了 灵活性,因此查询可以随每次运行而不同。
一个示例:
OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
OPENbound_cursor[ (argument_values) ];
这种形式的 OPEN 用于打开一个在声明时就已经绑定查询 的游标变量。该游标不能已经处于打开状态。当且仅当该游标被 声明为接收参数时,才必须提供实际参数值表达式列表。这些值 会被替换到查询中。 已绑定游标的查询计划始终被视为可缓存;在这种情况下没有与 EXECUTE 对应的形式。
示例:
OPEN curs2; OPEN curs3(42);
一旦一个游标已经被打开,那么就可以用这里描述的语句操作它。
这些操作不必发生在最初打开该游标的同一个函数中。你可以从函数 中返回一个 refcursor 值,让调用者来操作该游标。 (在内部,refcursor 值只是一个所谓 portal 的字符串 名称,该 portal 包含了该游标的活动查询。这个名称可以被传递、 赋给其他 refcursor 变量等等,而不会干扰该 portal。)
所有 portal 都会在事务结束时被隐式关闭。因此, refcursor 值只能在事务结束之前用于引用一个打开的 游标。
FETCHFETCHcursorINTOtarget;
FETCH 从游标中检索下一行到目标中,目标可以 是一个行变量、记录变量或者逗号分隔的简单变量列表,就像 SELECT INTO 一样。与 SELECT INTO 一样,可以检查特殊变量 FOUND 来看是否获得了一行。
示例:
FETCH curs1 INTO rowvar; FETCH curs2 INTO foo, bar, baz; FETCH LAST FROM curs3 INTO x, y; FETCH RELATIVE -2 FROM curs4 INTO x;
CLOSE
CLOSE cursor;
CLOSE 关闭打开游标所基于的 portal。这样就可以在事务结束之前提前释放资源,或者释放该 游标变量以便再次打开。
一个示例:
CLOSE curs1;
PL/pgSQL 函数可以向调用者返回游标。 这对于返回多行或多列,特别是非常大的结果集时很有用。要做到 这一点,函数需要打开游标,并把游标名返回给调用者(或者直接 使用调用者指定或已知的 portal 名称来打开游标)。随后调用者 就可以从该游标中提取行。游标既可以由调用者关闭,也会在事务 结束时自动关闭。
游标使用的 portal 名称既可以由程序员指定,也可以自动生成。 要指定 portal 名称,只需在打开 refcursor 变量之前给它赋一个字符串值。 OPEN 会把该 refcursor 变量的字符串值用作底层 portal 的名称。 不过,如果 refcursor 变量为 null, OPEN 就会自动生成一个与任何现有 portal 都 不冲突的名称,并把它赋回给 refcursor 变量。
已绑定游标变量会被初始化为表示其名称的字符串值,因此除非 程序员在打开游标之前通过赋值覆盖它,否则 portal 名称与 游标变量名相同。而未绑定游标变量在初始时默认为空值,因此 除非被覆盖,否则它会得到一个自动生成的唯一名称。
下面的示例展示了由调用者提供游标名称的一种方式:
CREATE TABLE test (col text);
INSERT INTO test VALUES ('123');
CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS '
BEGIN
OPEN $1 FOR SELECT col FROM test;
RETURN $1;
END;
' LANGUAGE plpgsql;
BEGIN;
SELECT reffunc('funccursor');
FETCH ALL IN funccursor;
COMMIT;
下面的示例使用了自动游标名称生成:
CREATE FUNCTION reffunc2() RETURNS refcursor AS '
DECLARE
ref refcursor;
BEGIN
OPEN ref FOR SELECT col FROM test;
RETURN ref;
END;
' LANGUAGE plpgsql;
BEGIN;
SELECT reffunc2();
reffunc2
--------------------
<unnamed cursor 1>
(1 row)
FETCH ALL IN "<unnamed cursor 1>";
COMMIT;
下面的示例展示了从单个函数返回多个游标的一种方式:
CREATE FUNCTION myfunc(refcursor, refcursor) RETURNS SETOF refcursor AS $$
BEGIN
OPEN $1 FOR SELECT * FROM table_1;
RETURN NEXT $1;
OPEN $2 FOR SELECT * FROM table_2;
RETURN NEXT $2;
RETURN;
END;
$$ LANGUAGE plpgsql;
-- need to be in a transaction to use cursors.
BEGIN;
SELECT * FROM myfunc('a', 'b');
FETCH ALL FROM a;
FETCH ALL FROM b;
COMMIT;
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。