PL/pgSQL 游标
在本教程中,您将了解 PL/pgSQL 游标以及如何使用它们逐行处理结果集。
摘要:在本教程中,您将了解 PL/pgSQL 游标以及如何使用它们逐行处理结果集。
PL/pgSQL 游标允许您封装查询并一次处理每一行。
通常,当您想要将一个大的结果集划分为多个部分并单独处理每个部分时,您可以使用游标。如果一次性处理,可能会出现内存溢出错误。
最重要的是,您可以开发一个函数来返回对游标的引用。这是从函数返回大结果集的有效方法。函数的调用者可以根据游标引用处理结果集。
下图说明了如何在 PostgreSQL 中使用游标:

- 首先,声明一个游标。
- 接下来,打开光标。
- 然后,将结果集中的行提取到目标中。
- 之后,检查是否还有更多的行要提取。如果是,则转至步骤 3,否则转至步骤 5。
- 最后,关闭光标。
我们将在以下各节中更详细地检查每个步骤。
声明游标
要访问游标,您需要在块的声明部分声明一个游标变量。PostgreSQL 为您提供了一种特殊类型,称为 REFCURSOR 声明游标变量。
declare my_cursor refcursor;
您还可以使用以下语法声明绑定到查询的游标:
cursor_name [ [no] scroll ] cursor [( name datatype, name data type, ...)] for query;
首先,为游标指定一个变量名。
接下来,您可以使用 指定光标是否可以向后滚动 SCROLL 。如果使用 NO SCROLL ,光标不能向后滚动。
然后,您将 CURSOR 关键字放在 name datatype 定义查询参数的逗号分隔参数列表 ( ) 之后。当游标打开时,这些参数将被值替换。
之后,您在 FOR 关键字后面指定一个查询。您可以在此处使用任何有效的SELECT 语句。
以下示例说明了如何声明游标:
declare
cur_films cursor for
select *
from film;
cur_films2 cursor (year integer) for
select *
from film
where release_year = year;
该 cur_films 是一个封装中的所有行的光标 film 表。
本 cur_films2 是同在一个特定的发行年份封装薄膜光标 film 表。
打开游标
游标必须先打开,然后才能用于查询行。PostgreSQL 提供了打开未绑定和绑定游标的语法。
打开未绑定的游标
您可以使用以下语法打开一个未绑定的游标:
OPEN unbound_cursor_variable [ [ NO ] SCROLL ] FOR query;
因为未绑定的游标变量在我们声明时没有绑定到任何查询,所以我们必须在打开它时指定查询。请参阅以下示例:
open my_cursor for
select * from city
where country = p_country;
PostgreSQL 允许您打开游标并将其绑定到动态查询。这是语法:
open unbound_cursor_variable[ [ no ] scroll ]
for execute query_string [using expression [, ... ] ];
在以下示例中,我们构建了一个基于 sort_field 参数对行进行排序的动态查询,并打开执行动态查询的游标。
query := 'select * from city order by $1';
open cur_city for execute query using sort_field;
打开绑定游标
因为绑定游标在我们声明它时已经绑定到查询,所以当我们打开它时,我们只需要在必要时将参数传递给查询。
open cursor_variable[ (name:=value,name:=value,...)];
在下面的例子中,我们打开绑定游标 cur_films 和 cur_films2 我们上面声明的:
open cur_films;
open cur_films2(year:=2005);
使用游标
打开游标后,我们可以使用 FETCH 、 MOVE 、UPDATE或DELETE语句对其进行操作。
获取下一行
fetch [ direction { from | in } ] cursor_variable
into target_variable;
该 FETCH 语句从游标中获取下一行并为其分配一个 target_variable ,它可以是一个记录、一个行变量或一个逗号分隔的变量列表。如果找不到更多行, target_variable 则设置为 NULL (s)。
默认情况下,如果您没有明确指定方向,游标会获取下一行。以下内容对游标有效:
- 下一个
- 最后的
- 事先的
- 第一的
- 绝对计数
- 相对计数
- 向前
- 落后
请注意, FORWARD 和 BACKWARD 方向仅适用于使用 SCROLL 选项声明的游标。
请参阅以下获取游标的示例。
fetch cur_films into row_film;
fetch last from row_film into title, release_year;
移动光标
move [ direction { from | in } ] cursor_variable;
如果只想移动游标而不检索任何行,请使用该 MOVE 语句。方向接受与 FETCH 语句相同的值。
move cur_films2;
move last from cur_films;
move relative -1 from cur_films;
move forward 3 from cur_films;
删除或更新行
定位游标后,我们可以使用 DELETE WHERE CURRENT OF or UPDATE WHERE CURRENT OF 语句删除或更新由游标标识的行,如下所示:
update table_name
set column = value, ...
where current of cursor_variable;
delete from table_name
where current of cursor_variable;
请参阅以下示例。
update film
set release_year = p_year
where current of cur_films;
关闭游标
要关闭打开的游标,我们使用 CLOSE 如下语句:
close cursor_variable;
该 CLOSE 语句释放资源或释放游标变量以允许使用 OPEN 语句再次打开它。
PL/pgSQL 游标——把它们放在一起
以下 get_film_titles(integer) 函数接受一个表示电影发行年份的参数。在函数内部,我们查询所有发行年份等于传递给函数的发行年份的电影。我们使用光标来遍历行并连接标题和标题包含 ful 该词的电影的发行年份。
create or replace function get_film_titles(p_year integer)
returns text as $$
declare
titles text default '';
rec_film record;
cur_films cursor(p_year integer)
for select title, release_year
from film
where release_year = p_year;
begin
-- open the cursor
open cur_films(p_year);
loop
-- fetch row into the film
fetch cur_films into rec_film;
-- exit when no more row to fetch
exit when not found;
-- build the output
if rec_film.title like '%ful%' then
titles := titles || ',' || rec_film.title || ':' || rec_film.release_year;
end if;
end loop;
-- close the cursor
close cur_films;
return titles;
end; $$
language plpgsql;
select get_film_titles(2006);
,Grosse Wonderful:2006,Day Unfaithful:2006,Reap Unfaithful:2006,Unfaithful Kill:2006,Wonderful Drop:2006
在本教程中,您学习了如何使用 PL/pgSQL 游标循环遍历一组行并单独处理每一行。