Firebird Cursors - 你为什么要用一个

Firebird Cursors - Why would you use one

在文档 here 中,给出了以下使用 cursor 的代码示例:

execute block
returns (
  relation char(31), 
  sysflag int)
as
declare cur cursor for 
  (select rdb$relation_name, rdb$system_flag from rdb$relations);
begin
  open cur;
  while (1=1) do
  begin
    fetch cur into relation, sysflag;
    if (row_count = 0) then leave;
    suspend;
  end
  close cur;
end

不过也可以这样操作:

execute block
returns (
  relation char(31), 
  sysflag int)
as
begin
  for select rdb$relation_name, rdb$system_flag 
  from rdb$relations 
  into relation, sysflag 
  do begin
    suspend;
  end
end

那么我为什么要使用一个呢?最终上面的例子甚至不需要 execlute block 因为它只是一个简单的 select 语句。所以我想这个例子太简单了,无法展示它的好处。

您 link(及其 newer 2.5 counterpart)的文档已经包含了您会(或不会)使用游标的大部分原因(强调我的):

If the cursor is needed only to walk the result set, it is nearly always easier and less error-prone to use a FOR SELECT statement with the AS CURSOR clause. Declared cursors must be explicitly opened, used to fetch data and closed. The context variable ROW_COUNT has to be checked after each fetch and, if its value is zero, the loop has to be terminated. A FOR SELECT statement checks it automatically.

Nevertheless, declared cursors provide a high level of control over sequential events and allow several cursors to be managed in parallel.

所以简而言之,你应该经常使用FOR SELECT,除非你需要同时访问多个游标,或者可能需要一些比简单循环更复杂的逻辑。它还可以在代码的多个部分重用相同的游标定义(尽管这可能表明您需要在多个存储过程中分解代码)。

一个工具的存在并不意味着它应该用于所有事情。

顺便说一句,FOR SELECT 也是一个游标,只是您没有明确控制它(它隐藏了大部分丑陋之处;))。

另一种可能使用游标的情况是当需要更新检索到的行时,查找或重新定位(确定确切的 WHERE 子句)行可能是一个问题。在这种情况下,您可以使用 FOR UPDATE 子句打开游标,并使用 WHERE CURRENT OF 子句更新(或删除)行。