# 43.7.光标

43.7.1. 声明游标变量

43.7.2. 打开游标

43.7.3. 使用游标

43.7.4. 循环浏览光标的结果

与其一次执行整个查询,还可以设置光标这将封装查询,然后一次读取几行查询结果。这样做的一个原因是,当结果包含大量行时,可以避免内存溢出。(然而,PL/pgSQL用户通常不需要担心这一点,因为对于循环会自动在内部使用光标以避免内存问题。)更有趣的用法是返回对函数创建的游标的引用,允许调用方读取行。这提供了一种从函数返回大行集的有效方法。

# 43.7.1.声明游标变量

PL/pgSQL中对游标的所有访问都通过游标变量进行,这些变量始终是特殊的数据类型参考光标.创建游标变量的一种方法是将其声明为类型为的变量参考光标。另一种方法是使用游标声明语法,通常是:

name [ [ NO ] SCROLL ] CURSOR [ ( arguments ) ] FOR query;

(对于可以替换为为了与Oracle兼容。)如果纸卷指定时,光标将能够向后滚动;如果没有卷轴指定时,将拒绝反向回迁;如果两个规范都没有出现,则是否允许反向回迁取决于查询。论据,如果指定,则为以逗号分隔的对列表*名称* *数据类型*定义要在给定查询中被参数值替换的名称。稍后,当光标打开时,将指定要替换这些名称的实际值。

例如:

DECLARE
    curs1 refcursor;
    curs2 CURSOR FOR SELECT * FROM tenk1;
    curs3 CURSOR (key integer) FOR SELECT * FROM tenk1 WHERE unique1 = key;

这三个变量都具有数据类型参考光标,但第一个查询可以用于任何查询,而第二个查询已经具有完全指定的查询跳跃最后一个绑定了一个参数化查询。(钥匙当光标打开时,将替换为整数参数值。)变量诅咒1据说是不受约束因为它不绑定到任何特定的查询。

这个纸卷当游标的查询使用更新/分享.此外,最好使用没有卷轴使用涉及易失性函数的查询。实施纸卷假设重新读取查询的输出将得到一致的结果,而volatile函数可能不会这样做。

# 43.7.2.打开游标

在使用光标检索行之前,它必须是开的(这是与SQL命令等效的操作声明游标PL/pgSQL有三种形式的打开语句,其中两个使用未绑定的游标变量,而第三个使用绑定的游标变量。

# 笔记

绑定的游标变量也可以通过对于中所述的声明第43.7.4节.

# 43.7.2.1. 开放 查询

OPEN unbound_cursorvar [ [ NO ] SCROLL ] FOR query;

游标变量被打开,并给出要执行的指定查询。游标不能已经打开,必须声明为未绑定的游标变量(即,作为简单变量)参考光标变量)。该查询必须是选择,或其他返回行的内容(例如解释)。该查询的处理方式与PL/pgSQL中的其他SQL命令相同:替换PL/pgSQL变量名,并缓存查询计划以供可能的重用。当PL/pgSQL变量被替换到游标查询中时,被替换的值就是它在查询时的值打开; 对变量的后续更改不会影响光标的行为。这个纸卷没有卷轴选项的含义与绑定光标的含义相同。

举个例子:

OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;

# 43.7.2.2. 开放执行

OPEN unbound_cursorvar [ [ NO ] SCROLL ] FOR EXECUTE query_string
                                     [ USING expression [, ... ] ];

游标变量被打开,并给出要执行的指定查询。游标不能已经打开,必须声明为未绑定的游标变量(即,作为简单变量)参考光标变量)。查询被指定为字符串表达式,方式与处决命令与往常一样,这提供了灵活性,因此查询计划可以在一次运行到下一次运行时有所不同(请参阅第43.11.2节),这也意味着没有对命令字符串进行变量替换。就像处决,参数值可以通过格式()使用这个纸卷没有卷轴选项的含义与绑定光标的含义相同。

举个例子:

OPEN curs1 FOR EXECUTE format('SELECT * FROM %I WHERE col1 = $1',tabname) USING keyvalue;

在本例中,表名通过格式().的比较值可乐1是通过使用参数,因此不需要引用。

# 43.7.2.3.打开绑定光标

OPEN bound_cursorvar [ ( [ argument_name := ] argument_value [, ...] ) ];

这种形式的打开用于打开一个游标变量,该变量的查询在声明时已绑定到该变量。光标无法打开。当且仅当游标被声明为接受参数时,必须出现实际参数值表达式的列表。这些值将在查询中被替换。

绑定游标的查询计划始终被认为是可缓存的;这是不可比拟的处决在这种情况下。注意纸卷没有卷轴无法在中指定打开,因为光标的滚动行为已经确定。

参数值可以通过以下两种方式传递:位置的命名的符号在位置表示法中,所有参数都是按顺序指定的。在命名表示法中,每个参数的名称使用:=将其与参数表达式分离。与调用函数类似,如中所述第4.3节,还允许混合使用位置符号和命名符号。

示例(使用上面的游标声明示例):

OPEN curs2;
OPEN curs3(42);
OPEN curs3(key := 42);

因为变量替换是在绑定游标的查询上完成的,所以实际上有两种方法可以将值传递给游标:或者使用显式参数打开,或通过在查询中隐式引用PL/pgSQL变量。但是,只有在声明绑定游标之前声明的变量才会被替换到绑定游标中。在任何一种情况下,要传递的值都是在发送时确定的打开.例如,另一种获得与诅咒3上面的例子是

DECLARE
    key integer;
    curs4 CURSOR FOR SELECT * FROM tenk1 WHERE unique1 = key;
BEGIN
    key := 42;
    OPEN curs4;

# 43.7.3.使用游标

一旦光标被打开,就可以用这里描述的语句对其进行操作。

这些操作不需要在打开光标的同一个函数中进行。你可以退货参考光标值,并让调用者对光标进行操作。(内部,a参考光标value只是所谓门户的字符串名,其中包含光标的活动查询。这个名字可以传给其他人参考光标变量等,而不会干扰门户。)

所有门户都在事务结束时隐式关闭。因此参考光标值仅在事务结束前可用于引用打开的游标。

# 43.7.3.1. 取来

FETCH [ direction { FROM | IN } ] cursor INTO target;

取来将光标中的下一行检索到目标中,目标可能是行变量、记录变量或逗号分隔的简单变量列表,如选择进入。如果没有下一行,则目标设置为空。就像选择进入,特殊变量建立可以检查是否获取了行。

这个*方向子句可以是SQL中允许的任何变体取来命令,但可以获取多行的命令除外;也就是说,它可以是下一个, 先前的, 第一, 最后的, 完全的 计数, 相对的 计数, 向前地向后的.省略方向与指定相同下一个.在表格中使用计数这个计数可以是任何整数值表达式(不同于SQL取来命令,该命令仅允许整数常量)。方向*需要向后移动的值可能会失败,除非使用纸卷选项

*光标*一定是一个参考光标引用打开的游标入口的变量。

例如:

FETCH curs1 INTO rowvar;
FETCH curs2 INTO foo, bar, baz;
FETCH LAST FROM curs3 INTO x, y;
FETCH RELATIVE -2 FROM curs4 INTO x;

# 43.7.3.2. 移动

MOVE [ direction { FROM | IN } ] cursor;

移动重新定位光标而不检索任何数据。移动工作原理与取来命令,但它只重新定位光标,不返回移动到的行。就像选择进入,特殊变量建立可以检查是否有下一行要移动。

例如:

MOVE curs1;
MOVE LAST FROM curs3;
MOVE RELATIVE -2 FROM curs4;
MOVE FORWARD 2 FROM curs4;

# 43.7.3.3. 更新/删除当前的

UPDATE table SET ... WHERE CURRENT OF cursor;
DELETE FROM table WHERE CURRENT OF cursor;

当光标位于表格行上时,可以使用光标来标识该行,从而更新或删除该行。游标的查询可能有限制(特别是没有分组),最好使用更新在光标中。有关更多信息,请参阅声明参考页。

举个例子:

UPDATE foo SET dataval = myval WHERE CURRENT OF curs1;

# 43.7.3.4. 

CLOSE cursor;

关闭打开光标下的门户。这可用于在事务结束之前释放资源,或释放游标变量以再次打开。

举个例子:

CLOSE curs1;

# 43.7.3.5.返回游标

PL/pgSQL函数可以将游标返回给调用方。这对于返回多行或多列非常有用,尤其是对于非常大的结果集。为此,函数打开游标并将游标名称返回给调用者(或者只使用调用者指定的或已知的入口名称打开游标)。然后,调用者可以从游标中提取行。调用方可以关闭光标,也可以在事务关闭时自动关闭光标。

用于游标的门户名称可以由程序员指定或自动生成。要指定门户名称,只需为参考光标变量,然后再打开它。字符串的字符串值参考光标变量将由打开作为基础门户的名称。然而,如果参考光标变量为空,打开自动生成与任何现有门户不冲突的名称,并将其分配给参考光标变量

# 笔记

绑定的游标变量被初始化为代表其名称的字符串值,因此门户名称与游标变量名称相同,除非程序员在打开游标之前通过赋值将其覆盖。但未绑定的游标变量最初默认为空值,因此除非被重写,否则它将接收自动生成的唯一名称。

以下示例显示了调用者提供光标名称的一种方式:

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;

-- need to be in a transaction to use cursors.
BEGIN;
SELECT reffunc2();

      reffunc2
### 43.7.4. Looping through a Cursor's Result

 There is a variant of the `FOR` statement that allows iterating through the rows returned by a cursor. The syntax is:

[ <<label>> ]对于绑定的\_cursorvar\[([参数名称:_]参数值[, ...])循环语句结束循环[标签];

 The cursor variable must have been bound to some query when it was declared, and it *cannot* be open already. The `FOR` statement automatically opens the cursor, and it closes the cursor again when the loop exits. A list of actual argument value expressions must appear if and only if the cursor was declared to take arguments. These values will be substituted in the query, in just the same way as during an `OPEN` (see [Section 43.7.2.3](plpgsql-cursors.html#PLPGSQL-OPEN-BOUND-CURSOR)).

 The variable *`recordvar`* is automatically defined as type `record` and exists only inside the loop (any existing definition of the variable name is ignored within the loop). Each row returned by the cursor is successively assigned to this record variable and the loop body is executed.