Postgresql 中文操作指南
Synopsis
DECLARE name [ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ]
CURSOR [ { WITH | WITHOUT } HOLD ] FOR query
Description
DECLARE 允许用户创建游标,该游标可用来一次从一个较大的查询中检索少量行。创建游标后,使用 FETCH 从中获取行。
Note
本页描述了 SQL 命令级别中游标的使用。如果你尝试在 PL/pgSQL 函数内使用游标,规则不同 — 请参阅 Section 43.7 。
Parameters
-
name
-
要创建的游标的名称。在会话中它一定不同于任何其他活动游标名称。
-
-
BINARY
-
导致游标以二进制格式而不是文本格式返回数据。
-
-
ASENSITIVE__INSENSITIVE
-
游标敏感性确定光标声明之后在同一事务中对光标所基于数据的更改是否在光标中可见。 INSENSITIVE 表示不可见, ASENSITIVE 表示行为与实现有关。PostgreSQL 中没有第三种行为, SENSITIVE ,表示此类更改在光标中可见。在 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 可按任何顺序显示。
Notes
普通光标以文本格式返回数据,与 SELECT 相同。 BINARY 选项指定光标应以二进制格式返回数据。这样可减少服务器和客户端的转换工作量,但会增加处理与平台相关的二进制数据格式的编程工作量。例如,如果一个查询从整数列中返回 1 的值,则使用默认光标时会得到一个 1 字符串,而使用二进制光标时会得到一个包含该值内部表示(大端字节序)的 4 字节字段。
应谨慎使用二进制光标。许多应用程序(包括 psql)尚无法处理二进制光标,并期望数据采用文本格式返回。
Note
当客户端应用程序使用“扩展查询”协议发出 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 。
Caution
如果可滚动游标调用任何不稳定函数(参见 Section 38.7 ),则它们可能会产生意外的结果。当重新获取以前获取的行时,可能会重新执行函数,从而产生与第一次不同的结果。最好针对涉及不稳定函数的查询指定 NO SCROLL 。如果这不可行,一种解决方法是在读取中的任何行之前声明游标为 SCROLL WITH HOLD 并提交事务。这会强制游标的整个输出保存在临时存储中,以便针对每行只执行一次不稳定函数。
如果游标的查询包含 FOR UPDATE 或 FOR SHARE ,则返回的行会像使用这些选项的常规 SELECT 命令一样,在初次获取时锁定。此外,返回的行将是最新的版本。
Caution
如果游标打算与 UPDATE … WHERE CURRENT OF 或 DELETE … WHERE CURRENT OF 一起使用,通常建议使用 FOR UPDATE 。使用 FOR UPDATE 可以防止其他会话在获取行的时间和更新时间之间更改行。如果不使用 FOR UPDATE ,则如果自创建游标以来该行已被更改,随后的 WHERE CURRENT OF 命令将不起作用。
使用 FOR UPDATE 的另一个原因是:如果没有它,如果游标查询不满足 SQL 标准的“可简单更新”规则(特别是,游标必须仅引用一个表,并且不使用分组或 ORDER BY ),则 WHERE CURRENT OF 可能会失败。不可简单更新的游标可能有效,也可能无效,具体取决于计划选择详细信息;因此在最坏的情况下,应用程序可能会在测试中正常运行,但在生产中失败。如果指定 FOR UPDATE ,则游标可以保证可更新。
不使用 WHERE CURRENT OF 配合使用 FOR UPDATE 的主要原因是你需要该游标具有可滚动性,或与并发更新隔离(即继续显示旧数据)。如果这是要求,请密切注意上面显示的警告。
SQL 标准仅为嵌入式 SQL 中的游标提供规定。PostgreSQL 服务器没有为游标实现 OPEN 语句;声明时,游标被认为已打开。然而,PostgreSQL 的嵌入式 SQL 预处理器 ECPG 支持标准 SQL 游标约定,包括涉及 DECLARE 和 OPEN 语句的约定。
作为打开游标基础的数据结构称为 portal 。门户名称在客户端协议中公开:如果知道门户名称,客户端可以直接从打开的门户中获取行。使用 DECLARE 创建游标时,门户名称与游标名称相同。
你可以通过查询 pg_cursors 系统视图来查看所有可用的游标。