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
不同。有关详细信息,请参阅下面的 Notes。
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
命令相同。此外,返回的行将是最新版本。
如果光标打算与 UPDATE ... WHERE CURRENT OF
或 DELETE ... WHERE CURRENT OF
一起使用,则通常建议使用 FOR UPDATE
。使用 FOR UPDATE
可以防止其他会话在获取行和更新行之间更改行。若没有 FOR UPDATE
,当自创建光标以来行已被更改,则后续的 WHERE CURRENT OF
命令将不起作用。
使用 FOR UPDATE
的另一个原因是如果没有它,后续的 WHERE CURRENT OF
可能会失败,如果游标查询不满足 SQL 标准作为 “简单可更新的” 的规则(特别是,光标必须只引用一个表,并且不使用分组或 ORDER BY
)。并不是简单可更新的光标可能会起作用,或者不会,这取决于计划选择详情;因此在最糟糕的情况下,应用程序可能会在测试中起作用,然后在产品中失败。如果指定了 FOR UPDATE
,则保证光标是可更新的。
不使用 FOR UPDATE
与 WHERE CURRENT OF
的主要原因是如果需要游标可滚动,或与并发更新隔离(也就是继续显示旧数据)。如果这是个要求,请密切注意上面显示的注意事项。
SQL 标准仅为嵌入式中的光标提供条款SQL。 PostgreSQL 服务器不为游标实现 OPEN
语句;游标被认为在声明时是打开的。但是,嵌入式 PostgreSQL 的 SQL 预处理器 ECPG 支持标准 SQL 光标约定,包括涉及 DECLARE
和 OPEN
语句的那些约定。
开放光标下层的服务器数据结构称为 门户。门户名称在客户端协议中公开:客户端能直接从一个开放的门户中获取行,如果它知道门户的名称。用 DECLARE
创建一个光标时,门户的名称与光标名称相同。
可以通过查询 pg_cursors
系统视图来查看所有可用的光标。
SQL 标准仅允许嵌入式中的光标SQL以及模块中。 PostgreSQL 允许交互地使用光标。
根据 SQL 标准,通过 UPDATE ... WHERE CURRENT OF
和 DELETE ... WHERE CURRENT OF
语句对不敏感游标进行的更改会在同一个光标中可见。 PostgreSQL 将这些语句视为所有其他更改数据的语句(因为它们在不敏感光标中不可见)
二进制游标是 PostgreSQL 扩展。