DECLARE — 定义一个游标
DECLAREname
[ BINARY ] [ INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FORquery
DECLARE
允许用户创建游标,游标可以被用来在大型查询暂停时检索少量的行。
游标被创建后,可以用FETCH
从中取得行。
这个页面描述在 SQL 命令层面上游标的用法。如果想要在 PL/pgSQL函数中使用游标,其规则是不同的 — 详见Section 43.7。
name
要创建的游标的名称。
BINARY
让游标返回二进制数据而不是返回文本格式数据。
INSENSITIVE
游标敏感性决定了是否更改为游标下面的数据,在同一事务中完成,当游标被声明后,在游标中可见。
INSENSITIVE
表示它们不可见,ASENSITIVE
表示行为是实现相关的。
第三个行为,SENSITIVE
,意味着此类更改在游标中可见,但在LightDB中不可用。
在LightDB中,所有游标都不敏感;因此这些关键字没有任何影响,并且只在兼容SQL标准时才被接受。
SCROLL
NO SCROLL
SCROLL
指定游标可以用非顺序(例如,反向)
的方式从中检索行。根据查询的执行计划的复杂度,指定
SCROLL
可能导致查询执行时间上的性能损失。
NO SCROLL
指定游标不能以非顺序的方式从中检索
行。默认是允许在某些情况下滚动,但这和指定
SCROLL
不完全相同。详情请见
Notes。
WITH HOLD
WITHOUT HOLD
WITH HOLD
指定该游标在创建它的事务提交
之后还能被继续使用。WITHOUT HOLD
指定该游标
不能在创建它的事务之外使用。如果两者都没有指定,则默认为
WITHOUT HOLD
。
query
关键词ASENSITIVE
、BINARY
、INSENSITIVE
和SCROLL
可以以任意顺序出现。
普通游标以文本格式返回数据,这和SELECT
产生的数据一样。
BINARY
选项指定游标应该以二进制格式返回数据。这减少了服务
器和客户端的转换负担,但程序员需要付出更多工作来处理与平台相关的二进制
数据格式。例如,如果一个查询从一个整数列中返回一个值一,用一个默认游标
将得到一个字符串1
,而使用一个二进制游标将得到该值的四字节
内部表示(big-endian 大端字节顺序)。
使用二进制游标时应该小心。很多应用(包括 ltsql)还没有准备好处理二进制游标, 它们仍然期待数据以文本格式到来。
当客户端应用使用“扩展查询”协议发出一个
FETCH
命令,绑定协议消息会指定使用文本还是
二进制格式检索数据。这种选择会覆盖定义游标时指定的方式。因此
在使用扩展查询协议时,这样一个二进制游标的概念实际是被废弃的
— 任何游标都可以被视作文本或者二进制。
除非指定了WITH HOLD
,这个命令创建的游标只能在当前事务中使用。
因此,没有WITH HOLD
的DECLARE
在事务块外是没有用的:游标只会生存到该语句结束。
因此如果这种命令在事务块之外被使用,LightDB会报告一个错误。
定义事务块需要使用BEGIN
和COMMIT
(或者ROLLBACK
)。
如果指定了WITH HOLD
并且创建游标的事务
成功提交,在同一个会话中的后续事务中还能够继续访问该游标(
但是如果创建事务被中止,游标会被移除)。一个用
WITH HOLD
创建的游标可以用一个显式的
CLOSE
命令关闭,或者会话结束时它
也会被关闭。在当前的实现中,由一个被保持游标表示的行会被复
制到一个临时文件或者内存区域中,这样它们才会在后续事务中保
持可用。
当查询包括FOR UPDATE
或FOR SHARE
时,
不能指定WITH HOLD
。
在定义一个将被反向取元组的游标时,应该指定SCROLL
选项。这是 SQL 标准所要求的。不过,为了和早期版本兼容,
如果游标的查询计划足够简单到支持它不需要额外的开销,
LightDB会允许在没有
SCROLL
的情况下反向取元组。不过,建议应用开发者
不要依赖于从没有用SCROLL
创建的游标中反向取
元组。如果指定了NO SCROLL
,那么任何情况下都不
允许反向取元组。
当查询包括FOR UPDATE
或FOR SHARE
时,
也不允许反向取元组。因此在这种情况下不能指定
SCROLL
。
如果可滚动游标调用了任何不稳定的函数(见Section 38.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
的原因是,如果没有它,当游标查询不符合
SQL 标准的“简单可更新”规则时,后续的
WHERE CURRENT OF
可能会失败(特别地,该游标必须只引用一个
表并且没有使用分组或者ORDER BY
)。不是简单可更新的游标可能
成功也可能不成功,这取决于计划选择的细节。因此在最坏的情况下,应用可能会
在测试时成功但是在生产中失败。如果指定了FOR UPDATE
,
则保证游标是可更新的。
不把FOR UPDATE
和WHERE CURRENT OF
一起用的主要原因是,需要游标时可滚动的,或者与当前的更新隔离(也就是说,继续显示旧的数据)。
如果这是你的需求,应密切关注安上述警示。
SQL 标准只对嵌入式SQL中的游标做出了规定。
LightDB服务器没有为游标实现
OPEN
语句。当游标被声明时就被认为已经
被打开。不过,ECPG(Oracle Pro*c兼容)(
LightDB的嵌入式 SQL 预处理器)
支持标准 SQL 游标习惯,包括那些DECLARE
和OPEN
语句。
你可以通过查询pg_cursors
系统视图可以看到所有可用的游标。
声明一个游标:
DECLARE liahona CURSOR FOR SELECT * FROM films; DECLARE liahona_1 scroll CURSOR FOR SELECT * FROM films for update; --error, Scrollable cursors must be READ ONLY DECLARE liahona_2 CURSOR FOR SELECT * FROM films for update; fetch next liahona_2; fetch prior liahona_2; --error, cursor can only scan forward
更多游标的例子请见FETCH。
SQL 标准规定,游标是否默认对底层数据的并发更新敏感取决于实现。
在 LightDB 中,默认情况下游标是不敏感的,
可以通过指定 FOR UPDATE
使其变得敏感。其他产品可能有不同的工作方式。
SQL 标准只允许在嵌入式 SQL 和模块中使用游标。 LightDB 允许交互式使用游标。
二进制游标是一种LightDB 扩展。