DECLARE — 定义一个游标
DECLAREname
[ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FORquery
DECLARE
允许用户创建游标,游标可用于一次性从一个大型查询中检索少量行。在创建游标后,可以使用 FETCH
命令从游标中获取行。
本文档描述了 SQL 命令级别的游标用法。如果您尝试在 PL/pgSQL 函数中使用游标,规则会有所不同——请参阅 第 41.7 节。
name
要创建的游标的名称。此名称必须与会话中的任何其他活动游标名称都不同。
BINARY
导致游标以二进制格式而不是文本格式返回数据。
ASENSITIVE
INSENSITIVE
游标的敏感性决定了在声明游标后,同一事务中对游标底层数据所做的更改是否对游标可见。INSENSITIVE
表示这些更改不可见,ASENSITIVE
表示行为取决于具体实现。第三种行为 SENSITIVE
(表示此类更改对游标可见)在 PostgreSQL 中不可用。在 PostgreSQL 中,所有游标都是不敏感的;因此,这些关键字没有实际作用,只是为了与 SQL 标准兼容而接受。
指定 INSENSITIVE
和 FOR UPDATE
或 FOR SHARE
是一个错误。
SCROLL
NO SCROLL
SCROLL
指定了游标可以用于非顺序地(例如,向后)检索行。根据查询执行计划的复杂性,指定 SCROLL
可能会对查询的执行时间造成性能损失。NO SCROLL
指定了游标不能用于非顺序地检索行。默认情况下允许在某些情况下进行滚动;这不等同于指定 SCROLL
。有关详细信息,请参见下面的 注释。
WITH HOLD
WITHOUT HOLD
WITH HOLD
指定了游标可以在创建它的事务成功提交后继续使用。WITHOUT HOLD
指定了游标不能在创建它的事务之外使用。如果既没有指定 WITHOUT HOLD
也没有指定 WITH HOLD
,则默认是 WITHOUT HOLD
。
query
关键字 ASENSITIVE
、BINARY
、INSENSITIVE
和 SCROLL
可以按任意顺序出现。
普通游标以文本格式返回数据,与 SELECT
生成的结果相同。BINARY
选项指定了游标应以二进制格式返回数据。这减少了服务器和客户端的转换开销,但需要程序员花费更多精力来处理依赖于平台的二进制数据格式。例如,如果一个查询从整数列返回值为 1,使用默认游标您将得到字符串 1
,而使用二进制游标您将得到一个 4 字节字段,其中包含该值的内部表示(采用大端字节序)。
应谨慎使用二进制游标。许多应用程序,包括 psql,都无法处理二进制游标,并且期望数据以文本格式返回。
当客户端应用程序使用“扩展查询”协议发出 FETCH
命令时,Bind 协议消息会指定数据是以文本格式还是二进制格式检索。此选择会覆盖游标的定义方式。因此,在使用扩展查询协议时,二进制游标的概念本身已过时——任何游标都可以被视为文本或二进制。
除非指定了 WITH HOLD
,否则此命令创建的游标只能在当前事务中使用。因此,在事务块之外使用不带 WITH HOLD
的 DECLARE
是无用的:游标仅在语句完成后生存。因此,如果在事务块外使用此类命令,PostgreSQL 会报告错误。请使用 BEGIN
和 COMMIT
(或 ROLLBACK
)来定义事务块。
如果指定了 WITH HOLD
并且创建游标的事务成功提交,则该游标可以被同一会话中的后续事务继续访问。(但如果创建事务被中止,则游标会被删除。)通过 WITH HOLD
创建的游标会在对其发出显式的 CLOSE
命令时关闭,或者在会话结束时关闭。在当前实现中,由保持的游标表示的行会被复制到临时文件或内存区域,以便它们可供后续事务使用。
当查询包含 FOR UPDATE
或 FOR SHARE
时,不能指定 WITH HOLD
。
当定义一个将用于向后提取的游标时,应指定 SCROLL
选项。这是 SQL 标准的要求。然而,为了与早期版本兼容,如果游标的查询计划足够简单,不需要额外的开销来支持它,PostgreSQL 将允许在没有 SCROLL
的情况下向后提取。但是,建议应用程序开发人员不要依赖于从未使用 SCROLL
创建的游标进行向后提取。如果指定了 NO SCROLL
,则无论如何都不允许向后提取。
当查询包含 FOR UPDATE
或 FOR SHARE
时,也禁止向后提取;因此,在这种情况下不能指定 SCROLL
。
当滚动游标调用任何易变函数时(参见 第 36.7 节),可能会产生意外结果。当重新提取先前已提取的行时,函数可能会被重新执行,可能导致结果与第一次不同。最好为涉及易变函数的查询指定 NO SCROLL
。如果不可行,一种解决方法是声明游标为 SCROLL WITH HOLD
并在读取游标中的任何行之前提交事务。这将强制游标的整个输出物化到临时存储中,从而确保易变函数对每一行只执行一次。
如果游标的查询包含 FOR UPDATE
或 FOR SHARE
,则在首次提取时会锁定返回的行,其方式与带有这些选项的普通 SELECT
命令相同。此外,返回的行将是最新的版本。
通常建议使用 FOR UPDATE
,如果游标打算与 UPDATE ... WHERE CURRENT OF
或 DELETE ... WHERE CURRENT OF
一起使用。使用 FOR UPDATE
可以防止其他会话在行被提取和更新之间更改这些行。如果没有 FOR UPDATE
,后续的 WHERE CURRENT OF
命令将在游标创建后行被更改时无效。
使用 FOR UPDATE
的另一个原因是,如果没有它,后续的 WHERE CURRENT OF
可能会失败,如果游标查询不满足 SQL 标准关于“简单可更新”的规则(特别是,游标必须只引用一个表,并且不能使用分组或 ORDER BY
)。不可简单更新的游标可能会工作,也可能不会,具体取决于计划选择的细节;因此,在最坏的情况下,应用程序在测试中可能会正常工作,然后在生产环境中失败。如果指定了 FOR UPDATE
,则游标保证是可更新的。
不将 FOR UPDATE
与 WHERE CURRENT OF
一起使用的主要原因是,如果您需要游标是可滚动的,或者需要与并发更新隔离(即,继续显示旧数据)。如果这是要求,请密切注意上面显示的注意事项。
SQL 标准仅为嵌入式 SQL 中的游标提供了规定。SQL。 PostgreSQL 服务器不实现游标的 OPEN
语句;声明游标时,它就被认为是打开的。但是,ECPG(PostgreSQL 的嵌入式 SQL 预处理器)支持标准的 SQL 游标约定,包括涉及 DECLARE
和 OPEN
语句的约定。
已打开游标的底层服务器数据结构称为 portal。Portal 名称在客户端协议中公开:如果客户端知道 portal 的名称,则可以直接从已打开的 portal 中获取行。使用 DECLARE
创建游标时,portal 名称与游标名称相同。
您可以通过查询 pg_cursors
系统视图来查看所有可用的游标。
SQL 标准只允许在嵌入式 SQLSQL和模块中使用游标。 PostgreSQL 允许交互式使用游标。
根据 SQL 标准,对不敏感游标的 UPDATE ... WHERE CURRENT OF
和 DELETE ... WHERE CURRENT OF
语句所做的更改在此游标中是可见的。 PostgreSQL 将这些语句视为所有其他数据更改语句,即它们在不敏感游标中是不可见的。
二进制游标是 PostgreSQL 的扩展。
如果您在文档中发现任何不正确、不符合您对特定功能的实际体验或需要进一步澄清的内容,请使用 此表格 来报告文档问题。