SQL COMMAND · 游标与预备语句
DECLARE
定义一个游标
DECLARE游标与预备语句引入 10(基线)现存至 20 devel1 次语法变更
- 动词
DECLARE- 对象
—- 分组
- 游标与预备语句
- 引入版本
- 10(基线)
- 状态
- 现存
- 语法变更次数
- 1
- 手册小节数
- 6
版本轨迹
相对 PostgreSQL 17 无变化。
语法铁道图 PostgreSQL 18
沿轨道从左向右阅读,分岔表示选择,绕行表示可选,回环表示重复。方框为参数,点击带下划线的参数可展开子规则。
语法概要
DECLAREname[ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FORquery
描述
参数
name要创建的游标名称。它必须与该会话中任何其他活动游标的名称不同。
BINARY使游标以二进制格式而不是文本格式返回数据。
ASENSITIVEINSENSITIVE游标的敏感性决定了在声明游标之后、于同一事务中对其底层数据所做的更改是否会在游标中可见。
INSENSITIVE表示这些更改不可见,ASENSITIVE表示这种行为取决于具体实现。第三种行为是SENSITIVE,表示这类更改在游标中可见,而PostgreSQL不支持这种行为。在PostgreSQL中,所有游标都是不敏感的,因此这些关键字不起作用,只是为兼容 SQL 标准而接受。将
INSENSITIVE与FOR UPDATE或FOR SHARE一起指定会报错。SCROLLNO SCROLLSCROLL指定游标可用于以非顺序方式(例如向后)取出行。根据查询执行计划的复杂程度,指定SCROLL可能会给查询执行带来性能开销。NO SCROLL指定游标不能以非顺序方式取出行。默认情况下只在某些情形下允许滚动,这与显式指定SCROLL并不相同。详见下文注解。WITH HOLDWITHOUT HOLDWITH 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。
小心
如果可滚动游标调用了任何易变函数(见第 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中的游标作出规定。PostgreSQL服务器没有为游标实现OPEN语句;游标在声明时即被视为打开。不过,ECPG是PostgreSQL的嵌入式 SQL 预处理器,它支持标准 SQL 的游标约定,包括涉及DECLARE和OPEN语句的那些约定。
打开的游标在服务器端的底层数据结构称为portal。客户端协议会暴露 portal 名称:只要知道该名称,客户端就可以直接从一个打开的 portal 中取出行。使用DECLARE创建游标时,portal 名称与游标名称相同。
可以通过查询pg_cursors 系统视图查看所有可用游标。
示例
兼容性
SQL 标准只允许在嵌入式SQL和模块中使用游标。PostgreSQL允许以交互方式使用游标。
根据 SQL 标准,通过UPDATE ... WHERE CURRENT OF和DELETE ... WHERE CURRENT OF语句对不敏感游标所做的更改,在同一个游标中是可见的。PostgreSQL将这些语句与所有其他更改数据的语句同等对待,因此这些更改在不敏感游标中不可见。
二进制游标是PostgreSQL的一种扩展。
另见
语法演化
相邻大版本之间的差异,新的在前。版本号链接到对应快照。
PostgreSQL 17← 16正文更新
正文更新PostgreSQL 16← 15正文更新
正文更新PostgreSQL 14← 13语法变化
+ DECLARE name [ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ]正文更新PostgreSQL 12← 11正文更新
正文更新PostgreSQL 11← 10正文更新
正文更新