DECLARE
DECLARE — 定义一个游标
大纲
DECLAREname[ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FORquery
描述
DECLARE 允许用户创建游标,游标可用于从较大的查询中一次取出少量行。游标创建后,可使用 FETCH 从中取出行。
注意
本页面描述的是 SQL 命令层面的游标用法。如果想要在 PL/pgSQL 函数中使用游标,规则会有所不同 — 见第 43.7 节。
参数
name#要创建的游标名称。
BINARY#使游标以二进制格式而不是文本格式返回数据。
ASENSITIVEINSENSITIVE#游标的敏感性决定了在声明游标之后、于同一事务中对其底层数据所做的更改是否会在游标中可见。
INSENSITIVE表示这些更改不可见,ASENSITIVE表示这种行为取决于具体实现。第三种行为是SENSITIVE,表示这类更改在游标中可见,而 PostgreSQL 不支持这种行为。在 PostgreSQL 中,所有游标都是不敏感的,因此这些关键字不起作用,只是为兼容 SQL 标准而接受。将
INSENSITIVE与FOR UPDATE或FOR SHARE一起指定会报错。SCROLLNO SCROLL#SCROLL指定游标可用于以非顺序方式(例如向后)取出行。根据查询执行计划的复杂程度,指定SCROLL可能会给查询执行带来性能开销。NO SCROLL指定游标不能以非顺序方式取出行。默认情况下只在某些情形下允许滚动,这与显式指定SCROLL并不相同。详见下文注解。WITH HOLDWITHOUT 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,否则该命令创建的游标只能在当前事务中使用。因此,DECLARE 若不带 WITH HOLD,在事务块之外就毫无用处:游标只能存活到该语句执行完成。所以,如果在事务块之外使用这种命令,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。
小心
如果可滚动游标调用了任何易变函数(见第 38.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 中的游标作出规定。PostgreSQL 服务器没有为游标实现 OPEN 语句;游标在声明时即被视为打开。不过,ECPG 是 PostgreSQL 的嵌入式 SQL 预处理器,它支持标准 SQL 的游标约定,包括涉及 DECLARE 和 OPEN 语句的那些约定。
可以通过查询 pg_cursors
系统视图查看所有可用游标。
兼容性
SQL 标准只允许在嵌入式 SQL 和模块中使用游标。PostgreSQL 允许以交互方式使用游标。
根据 SQL 标准,通过 UPDATE ... WHERE CURRENT OF 和 DELETE ... WHERE CURRENT OF 语句对不敏感游标所做的更改,在同一个游标中是可见的。PostgreSQL 将这些语句与所有其他更改数据的语句同等对待,因此这些更改在不敏感游标中不可见。
二进制游标是 PostgreSQL 的一种扩展。
报告文档问题
阅读 上游文档. 通过 PostgreSQL 文档反馈表单.