2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

DECLARE

DECLARE — 定义一个游标

概要

DECLARE name [ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ]
    CURSOR [ { WITH | WITHOUT } HOLD ] FOR query

描述

DECLARE 允许用户创建游标,游标可用于一次性从一个大型查询中检索少量行。在创建游标后,可以使用 FETCH 命令从游标中获取行。

注意

本文档描述了 SQL 命令级别的游标用法。如果您尝试在 PL/pgSQL 函数中使用游标,规则会有所不同——请参阅 第 41.7 节

参数

name

要创建的游标的名称。此名称必须与会话中的任何其他活动游标名称都不同。

BINARY

导致游标以二进制格式而不是文本格式返回数据。

ASENSITIVE
INSENSITIVE

游标的敏感性决定了在声明游标后,同一事务中对游标底层数据所做的更改是否对游标可见。INSENSITIVE 表示这些更改不可见,ASENSITIVE 表示行为取决于具体实现。第三种行为 SENSITIVE(表示此类更改对游标可见)在 PostgreSQL 中不可用。在 PostgreSQL 中,所有游标都是不敏感的;因此,这些关键字没有实际作用,只是为了与 SQL 标准兼容而接受。

指定 INSENSITIVEFOR UPDATEFOR SHARE 是一个错误。

SCROLL
NO SCROLL

SCROLL 指定了游标可以用于非顺序地(例如,向后)检索行。根据查询执行计划的复杂性,指定 SCROLL 可能会对查询的执行时间造成性能损失。NO SCROLL 指定了游标不能用于非顺序地检索行。默认情况下允许在某些情况下进行滚动;这不等同于指定 SCROLL。有关详细信息,请参见下面的 注释

WITH HOLD
WITHOUT HOLD

WITH HOLD 指定了游标可以在创建它的事务成功提交后继续使用。WITHOUT HOLD 指定了游标不能在创建它的事务之外使用。如果既没有指定 WITHOUT HOLD 也没有指定 WITH HOLD,则默认是 WITHOUT HOLD

query

一个 SELECTVALUES 命令,它将提供由游标返回的行。

关键字 ASENSITIVEBINARYINSENSITIVESCROLL 可以按任意顺序出现。

注释

普通游标以文本格式返回数据,与 SELECT 生成的结果相同。BINARY 选项指定了游标应以二进制格式返回数据。这减少了服务器和客户端的转换开销,但需要程序员花费更多精力来处理依赖于平台的二进制数据格式。例如,如果一个查询从整数列返回值为 1,使用默认游标您将得到字符串 1,而使用二进制游标您将得到一个 4 字节字段,其中包含该值的内部表示(采用大端字节序)。

应谨慎使用二进制游标。许多应用程序,包括 psql,都无法处理二进制游标,并且期望数据以文本格式返回。

注意

当客户端应用程序使用“扩展查询”协议发出 FETCH 命令时,Bind 协议消息会指定数据是以文本格式还是二进制格式检索。此选择会覆盖游标的定义方式。因此,在使用扩展查询协议时,二进制游标的概念本身已过时——任何游标都可以被视为文本或二进制。

除非指定了 WITH HOLD,否则此命令创建的游标只能在当前事务中使用。因此,在事务块之外使用不带 WITH HOLDDECLARE 是无用的:游标仅在语句完成后生存。因此,如果在事务块外使用此类命令,PostgreSQL 会报告错误。请使用 BEGINCOMMIT(或 ROLLBACK)来定义事务块。

如果指定了 WITH HOLD 并且创建游标的事务成功提交,则该游标可以被同一会话中的后续事务继续访问。(但如果创建事务被中止,则游标会被删除。)通过 WITH HOLD 创建的游标会在对其发出显式的 CLOSE 命令时关闭,或者在会话结束时关闭。在当前实现中,由保持的游标表示的行会被复制到临时文件或内存区域,以便它们可供后续事务使用。

当查询包含 FOR UPDATEFOR SHARE 时,不能指定 WITH HOLD

当定义一个将用于向后提取的游标时,应指定 SCROLL 选项。这是 SQL 标准的要求。然而,为了与早期版本兼容,如果游标的查询计划足够简单,不需要额外的开销来支持它,PostgreSQL 将允许在没有 SCROLL 的情况下向后提取。但是,建议应用程序开发人员不要依赖于从未使用 SCROLL 创建的游标进行向后提取。如果指定了 NO SCROLL,则无论如何都不允许向后提取。

当查询包含 FOR UPDATEFOR SHARE 时,也禁止向后提取;因此,在这种情况下不能指定 SCROLL

注意

当滚动游标调用任何易变函数时(参见 第 36.7 节),可能会产生意外结果。当重新提取先前已提取的行时,函数可能会被重新执行,可能导致结果与第一次不同。最好为涉及易变函数的查询指定 NO SCROLL。如果不可行,一种解决方法是声明游标为 SCROLL WITH HOLD 并在读取游标中的任何行之前提交事务。这将强制游标的整个输出物化到临时存储中,从而确保易变函数对每一行只执行一次。

如果游标的查询包含 FOR UPDATEFOR SHARE,则在首次提取时会锁定返回的行,其方式与带有这些选项的普通 SELECT 命令相同。此外,返回的行将是最新的版本。

注意

通常建议使用 FOR UPDATE,如果游标打算与 UPDATE ... WHERE CURRENT OFDELETE ... WHERE CURRENT OF 一起使用。使用 FOR UPDATE 可以防止其他会话在行被提取和更新之间更改这些行。如果没有 FOR UPDATE,后续的 WHERE CURRENT OF 命令将在游标创建后行被更改时无效。

使用 FOR UPDATE 的另一个原因是,如果没有它,后续的 WHERE CURRENT OF 可能会失败,如果游标查询不满足 SQL 标准关于“简单可更新”的规则(特别是,游标必须只引用一个表,并且不能使用分组或 ORDER BY)。不可简单更新的游标可能会工作,也可能不会,具体取决于计划选择的细节;因此,在最坏的情况下,应用程序在测试中可能会正常工作,然后在生产环境中失败。如果指定了 FOR UPDATE,则游标保证是可更新的。

不将 FOR UPDATEWHERE CURRENT OF 一起使用的主要原因是,如果您需要游标是可滚动的,或者需要与并发更新隔离(即,继续显示旧数据)。如果这是要求,请密切注意上面显示的注意事项。

SQL 标准仅为嵌入式 SQL 中的游标提供了规定。SQLPostgreSQL 服务器不实现游标的 OPEN 语句;声明游标时,它就被认为是打开的。但是,ECPGPostgreSQL 的嵌入式 SQL 预处理器)支持标准的 SQL 游标约定,包括涉及 DECLAREOPEN 语句的约定。

已打开游标的底层服务器数据结构称为 portal。Portal 名称在客户端协议中公开:如果客户端知道 portal 的名称,则可以直接从已打开的 portal 中获取行。使用 DECLARE 创建游标时,portal 名称与游标名称相同。

您可以通过查询 pg_cursors 系统视图来查看所有可用的游标。

示例

声明游标

DECLARE liahona CURSOR FOR SELECT * FROM films;

有关游标用法的更多示例,请参见 FETCH

兼容性

SQL 标准只允许在嵌入式 SQLSQL和模块中使用游标。 PostgreSQL 允许交互式使用游标。

根据 SQL 标准,对不敏感游标的 UPDATE ... WHERE CURRENT OFDELETE ... WHERE CURRENT OF 语句所做的更改在此游标中是可见的。 PostgreSQL 将这些语句视为所有其他数据更改语句,即它们在不敏感游标中是不可见的。

二进制游标是 PostgreSQL 的扩展。

另请参阅

CLOSEFETCHMOVE

提交更正

如果您在文档中发现任何不正确、不符合您对特定功能的实际体验或需要进一步澄清的内容,请使用 此表格 来报告文档问题。