FOREACH 循环定义游标

FOREACH 循环以 FOREACH 关键字开始,并以 END FOREACH 结束。在 FOREACH 与 END FOREACH 之间,您可声明游标或使用 EXECUTE PROCEDURE 或 EXECUTE FUNCTION。下图中的两个示例展示 FOREACH 循环的结构。

图: FOREACH 循环的结构。

FOREACH cursor FOR
            SELECT column INTO variable FROM table 
            . . .
            END FOREACH;
            
            FOREACH 
            EXECUTE FUNCTION name() INTO variable;
            END FOREACH;
下图创建使用 FOREACH 循环的例程来在 employee 表上操作。

图: 对 employee 表操作的 FROEACH 循环。

CREATE_PROCEDURE increase_by_pct( pct INTEGER )
            DEFINE s INTEGER;
            
            FOREACH sal_cursor FOR
            SELECT salary INTO s FROM employee 
            WHERE salary > 35000
            LET s = s + s * ( pct/100 );
            UPDATE employee SET salary = s
            WHERE CURRENT OF sal_cursor;
            END FOREACH;
            
            END PROCEDURE;
前图中的例程执行 FOREACH 内的这些任务:
  • 声明游标
  • 一次从 employee 表选择一个 salary
  • 按百分率提高 salary
  • 以新的 salary 更新 employee
  • 访存下一个 salary 值

将 SELECT 语句放置在游标内,因为它返回表中所有大于 35000 的薪酬。

UPDATE 语句中的 WHERE CURRENT OF 子句仅更新该游标当前定位在其上的行,并在当前行上设置更新游标。更新游标在该行上放置更新锁,以便于其他用户不可更新该行,直到您的更新发生为止。

如果 FOREACH 循环内的 UPDATE 或 DELETE 语句使用 WHERE CURRENT OF 子句,则 SPL 例程将自动地设置更新游标。如果您使用 WHERE CURRENT OF,则必须显式地引用 FOREACH 语句内的游标。如果您正在使用更新游标,则可在 FOREACH 语句之前添加 BEGIN WORK 语句,并在 END FOREACH 之后添加 COMMIT WORK 语句,如下图所示。

图: 自动地设置更新游标。

BEGIN WORK;
            FOREACH sal_cursor FOR
            SELECT salary INTO s FROM employee WHERE salary > 35000;
            LET s = s + s * ( pct/100 );
            UPDATE employee SET salary = s WHERE CURRENT OF sal_cursor
            END FOREACH;
            COMMIT WORK;

对于前图中 FOREACH 循环的每一迭代,需要新锁(如果您使用行级别锁定的话)。在 FOREACH 循环的最后迭代之后,COMMIT WORK 语句释放所有的锁(并将所有更新了的行作为单个事务提交)。

要在循环的每一迭代之后提交更新了的行,您必须打开游标 WITH HOLD,并在 FOREACH 循环包括 BEGIN WORK 和 COMMIT WORK 语句,如下列 SPL 例程那样。

图: 在循环的每一迭代之后提交更新了的行。

CREATE PROCEDURE serial_update();
            DEFINE p_col2 INT;
            DEFINE i INT;
            LET i = 1;
            FOREACH cur_su WITH HOLD FOR
            SELECT col2 INTO p_col2 FROM customer WHERE 1=1
            BEGIN WORK;
            UPDATE customer SET customer_num = p_col2 WHERE CURRENT OF cur_su;
            COMMIT WORK;
            LET i = i + 1;
            END FOREACH;
            END PROCEDURE;

SPL 例程 serial_update() 提交每一行作为分开的事务。