游标
游标是对查询结果集的引用,允许您一次查看一行结果。游标记住结果集中的位置,可以是以下位置之一:
-
结果行
-
第一行之前
-
最后一行之后
您还可以使用 FOR 循环在未打开的绑定游标上进行迭代。有关详细信息,请参阅控制流。
声明游标
绑定游标
要将游标绑定到声明中的语句,请使用 FOR 关键字:
cursor_name CURSOR [ ( arg_name arg_type [, ...] ) ] FOR statement;
游标的实参使您能够更好地控制要处理的行。例如,假设您有下表:
=> SELECT * FROM coordinates_xy;
x | y
---+----
1 | 2
9 | 5
7 | 13
...
(100000 rows)
如果仅对 y
为 6 的行感兴趣,则可以声明以下游标,然后在打开游标时提供实参 6
:
c CURSOR (key int) FOR SELECT * FROM coordinates_xy WHERE y=key;
未绑定的游标
要声明未绑定到特定查询的游标,请使用 refcursor
类型:
cursor_name refcursor;
您可以随时使用打开对未绑定的游标进行绑定。
例如,要声明游标 my_unbound_cursor
:
my_unbound_cursor refcursor;
打开和关闭游标
打开
打开游标将使用给定实参执行查询,并将游标放在结果集的第一行之前。查询结果的排序(因此结果集的开头)是不确定的,除非您指定了 ORDER BY 子句。
打开绑定的游标
打开声明期间绑定的游标:
OPEN bound_cursor [ ( [ arg_name := ] arg_value [, ...] ) ];
例如,给定以下声明:
c CURSOR (key int) FOR SELECT * FROM t1 WHERE y=key;
可以使用以下某项操作打开游标:
OPEN c(5);
OPEN c(key := 5);
关闭
当游标离开范围时,打开的游标将自动关闭,但您可以使用“关闭”命令提前关闭游标。关闭的游标可以稍后重新打开,这将重新执行查询并准备新的结果集。
CLOSE cursor;
打开未绑定的游标
对未绑定的游标进行绑定,然后打开游标:
OPEN unbound_cursor FOR statement;
您还可以使用 EXECUTE,因为它是语句:
OPEN unbound_cursor FOR EXECUTE statement_string [ USING expression [, ... ] ];
例如,将游标 c
绑定到表 product_data
的查询:
OPEN c for SELECT * FROM product_data;
提取行
FETCH 语句:
-
检索指定游标当前指向的行,并将其存储在某个变量中。
-
使游标前进到下一个位置。
variable [, ...] := FETCH opened_cursor;
检索的值存储在变量中。行通常有多个值,因此您可以每行使用一个变量。
如果 FETCH 成功检索值,则特殊变量 FOUND 设置为 true
。否则,如果您在游标经过结果集的最后一行时调用 FETCH,它将返回 NULL,且特殊变量 FOUND 设置为 false
。
下面的过程创建游标 c
,将其绑定到 coordinates
表中的 SELECT 查询。该过程将实参 1 传递给游标,因此游标仅检索 y 坐标为 1 的行,将坐标存储在变量 x_
、y_
和 z_
中。
只有两行的 y 坐标为 1,因此使用 FETCH 两次后,第三个 FETCH 开始返回 NULL 值,且 FOUND 设置为 false
:
=> SELECT * FROM coordinates;
x | y | z
----+---+----
14 | 6 | 19
1 | 6 | 2
10 | 6 | 39
10 | 2 | 1
7 | 1 | 10
67 | 1 | 77
(6 rows)
DO $$
DECLARE
c CURSOR (key int) FOR SELECT * FROM coordinates WHERE y=key;
x_ int;
y_ int;
z_ int;
BEGIN
OPEN c(1); -- only retrieve rows where y=1
x_,y_,z_ := FETCH c;
RAISE NOTICE 'cursor returned %, %, %, FOUND=%',x_, y_, z_, FOUND;
x_,y_,z_ := FETCH c; -- fetches the last set of results and moves to the end of the result set
RAISE NOTICE 'cursor returned %, %, %, FOUND=%',x_, y_, z_, FOUND;
x_,y_,z_ := FETCH c; -- cursor has advanced past the final row
RAISE NOTICE 'cursor returned %, %, %, FOUND=%',x_, y_, z_, FOUND;
END;
$$;
NOTICE 2005: cursor returned 7, 1, 10, FOUND=t
NOTICE 2005: cursor returned 67, 1, 77, FOUND=t
NOTICE 2005: cursor returned <NULL>, <NULL>, <NULL>, FOUND=f
移动游标
MOVE 使打开的游标前进到下一个位置,而不检索该行。如果游标位置(在 MOVE 之前)未经过最后一行,则特殊 FOUND 变量设置为 true
— 即,如果调用 FETCH 而不调用 MOVE,则会检索该行。
MOVE bound_cursor;
例如,此游标仅检索 y 坐标为 2 的行。结果集只有一行,因此使用 MOVE 两次会导致前进超过第一行(和最后一行),且将 FOUND 设置为 false:
=> SELECT * FROM coordinates WHERE y=2;
x | y | z
----+---+---
10 | 2 | 1
(1 row)
DO $$
DECLARE
c CURSOR (key int) FOR SELECT * FROM coordinates WHERE y=key;
BEGIN
OPEN c(2); -- only retrieve rows where y=2, cursor starts before the first row
MOVE c; -- cursor advances to the first (and last) row
RAISE NOTICE 'FOUND=%', FOUND; -- FOUND is true because the cursor points to a row in the result set
MOVE c; -- cursor advances past the final row
RAISE NOTICE 'FOUND=%', FOUND; -- FOUND is false because the cursor is past the final row
END;
$$;
NOTICE 2005: FOUND=t
NOTICE 2005: FOUND=f