DECLARE CURSOR

DECLARE CURSOR 语句定义游标。

调用

此语句只能嵌入到应用程序中。 它不是可执行语句。 不得在 Java™中指定该值。

授权

不需要授权即可使用此语句。 但是,要对游标使用 OPEN 或 FETCH ,语句的授权标识所拥有的特权必须至少包含下列其中一项:

  • 对于游标的 SELECT 语句中标识的每个表或视图:
    • 对表或视图的 SELECT 特权,以及
    • 对包含表或视图的模式的 USAGE 特权
  • 数据库管理员权限

游标的 SELECT 语句是下列其中一项:

  • statement-name标识的预编译 select-statement
  • 指定的 select-statement

如果指定了 statement-name :

  • 除非在创建程序时在 CRTSQLxxx 命令上指定了 USRPRF (*OWNER) 和 DYNUSRPRF (*OWNER) ,否则该语句的授权标识是运行时授权标识。 有关更多信息,请参阅 授权标识和授权名称
  • 当准备 select-statement 时执行授权检查,除非在 CRTSQLxxx 命令上指定了 DLYPRP (*YES)。
  • 当为使用 DLYPRP (*YES) 参数编译的程序打开游标时,将执行授权检查。

如果指定了 select-statement :

  • 如果在 CRTSQLxxx 命令上指定了带有 SQL 命名的 USRPRF (*OWNER) 或 USRPRF (*NAMING) ,那么该语句的授权标识是 SQL 程序或程序包的所有者。
  • 如果在 CRTSQLxxx 命令上指定了带有系统命名的 USRPRF (*USER) 或 USRPRF (*NAMING) ,那么该语句的授权标识是运行时授权标识。
  • 在 REXX 中,语句的授权标识是运行时授权标识。
  • 打开游标时执行授权检查。

有关对应于 SQL 特权的系统权限的信息,请参阅 检查对表或视图的特权时的对应系统权限

语法

读取语法图跳过可视语法图DECLARE游标名ASENSITIVEINSENSITIVESENSITIVEDYNAMICNO SCROLLSCROLLCURSORWITHOUT HOLDWITH HOLDWITHOUT RETURNWITH RETURNTO CALLERTO CLIENTWITHOUT EXTENDED INDICATORSWITH EXTENDED INDICATORS1FOR SELECT 语句语句名
注:
  • 1 可以按任何顺序指定 HOLD , RETURN 和 EXTENDED 指示符子句。

描述

游标名
命名游标。 该名称不能与源程序中声明的另一个游标的名称相同。
ASENSITIVE, SENSITIVE, INSENSITIVE
指定游标是对更改敏感,敏感还是不敏感。 如果指定了 statement-name ,那么缺省值为语句的相应 prepare 属性。 否则,缺省值为 ASENSITIVE。
敏感性
指定根据 select-statement 的优化方式,游标可以作为 SENSITIVE 或 INSENSITIVE。
敏感
指定在打开游标后对数据库所作的更改在结果表中可视。 打开游标后,对于针对其结果表下的行进行任何更改或删除,游标会有一定的敏感。 游标对使用同一游标进行定位更新或删除始终敏感。 此外,游标可能会对此游标外进行的更改敏感。 如果数据库管理器不能使更改对游标可视,那么会返回错误。 当游标隐式变为只读时,数据库管理器不能使更改对游标可视。 (请参阅 游标的结果表。) 如果指定了 SENSITIVE ,那么 SELECT 语句不能包含 data-change-table-reference
不敏感
指定一旦打开游标,它就不具有对此激活组或任何其他激活组执行的插入,更新或删除的敏感度。 如果指定了 INSENSITIVE,那么游标是只读的,并且会在打开游标时创建临时结果。 此外, SELECT 语句不能包含 UPDATE 子句。
无滚动 滚动
指定游标是可滚动还是不可滚动。 如果指定了 statement-name ,那么缺省值为语句的相应 prepare 属性。 否则,缺省值为 NO 滚动。
无滚动
指定游标不可滚动。
卷动
指定游标可滚动。
WITHOUT HOLD WITH HOLD
指定是否应防止因落实操作而关闭游标。 如果指定了 statement-name ,那么缺省值为语句的相应 prepare 属性。 否则,缺省值为 WITHOUT HOLD。
无保留
不阻止由于落实操作而关闭游标。
WITH HOLD
防止由于落实操作而关闭游标。 仅当在落实操作期间结束与游标相关联的连接时,才会在落实时隐式关闭使用 WITH HOLD 子句声明的游标。

当指定 WITH HOLD 时,落实操作将落实当前工作单元中的所有更改,并释放除维护游标位置所需的锁定以外的所有锁定。 之后,需要 FETCH 语句,然后才能执行定位 UPDATE 或 DELETE 语句。

所有游标都由 CONNECT (类型 1) 或回滚操作隐式关闭。 与连接关联的所有游标都将通过断开连接而隐式关闭。 如果未指定 WITH HOLD ,或者如果与游标相关联的连接处于释放暂挂状态,那么落实操作也会隐式关闭游标。

如果在落实操作之前关闭了游标,那么效果与未使用 WITH HOLD 选项声明游标时的效果相同。

不带返回
指定要将游标的结果表用作过程结果集。 如果指定了 statement-name ,那么缺省值为语句的相应 prepare 属性。 否则,缺省值为 WITHOUT RETURN。
不返回
指定游标的结果表不打算用作过程结果集。
带返回
指定要将游标的结果表用作过程结果集。 如果过程的源代码中未包含 DECLARE CURSOR 语句,那么将忽略该子句。
对于 SQL 过程,仅当在过程定义上指定了具有非零最大结果集数的 DYNAMIC RESULT SETS 子句时,才会返回结果集。
  • 使用 WITH RETURN 子句定义的游标,这些游标在过程结束时仍处于打开状态,用于定义过程的结果集。 当该过程结束时,将关闭所有其他打开的游标,前提是该过程不是使用 CLOSQLCSR (*ENDACTGRP) 创建的。
  • 如果没有使用 WITH RETURN 或 WITHOUT RETURN 子句定义存储过程中的游标,那么在存储过程结束时打开的任何游标都可能成为结果集游标。
  • 请参阅 CREATE PROCEDURE (SQL) 中的 DYNAMIC RESULT SETS 子句,以了解确定过程结果集的进一步注意事项。
对于外部过程:
  • 任何使用 WITH RETURN 子句定义的游标 (或在 SET RESULT SETS 语句中标识为结果集游标) ,并且在过程结束时仍处于打开状态的游标定义过程的潜在结果集,前提是该过程不是使用 CLOSQLCSR (*ENDACTGRP) 创建的。 所有其他打开的游标都保持打开状态。
  • 如果未使用 WITH RETURN 或 WITHOUT RETURN 子句定义存储过程中的任何游标,并且未将任何游标标识为 SET RESULT SETS 语句中的结果集游标,那么在存储过程结束时打开的任何游标都可能成为结果集游标。
  • 请参阅 CREATE PROCEDURE (外部) 中的 DYNAMIC RESULT SETS 子句,以了解确定过程结果集的进一步注意事项。

对于不可滚动的游标,结果集由从当前光标位置到结果表末尾的所有行组成。 对于可滚动游标,结果集由结果表的所有行组成。

至呼叫者
指定游标可以将结果集返回给过程的调用者。 例如,如果调用者是客户机应用程序,那么结果集将返回到客户机应用程序。
至客户机
指定游标可以将结果集返回到客户机应用程序。 此游标对于任何中间嵌套过程都是不可见的。 如果直接或间接调用过程的函数或触发器,那么无法将结果集返回到客户机,并且在过程完成后将关闭游标。

如果从具有多个模块的 ILE 程序返回结果集,那么可能需要 TO CLIENT。

没有扩展指示符 或具有扩展指示符的
指定是否启用扩展指示符。 如果指定了 statement-name ,那么缺省值为语句的相应 prepare 属性。 否则,缺省值是在包含程序或服务程序上指定的属性。
无扩展指标
指定不启用扩展指示符变量,并且在隐式或显式 UPDATE 子句或 select-statement中只允许可更新的列。
使用扩展指标
指定启用扩展指示符变量,并且在 select-statement的隐式或显式 UPDATE 子句中允许不可更新的列。
SELECT 语句
指定游标的 SELECT 语句。 有关更多信息,请参阅 select-statement

select-statement 不得包含参数标记 (REXX 除外) ,但可以包含对变量的引用。 在主语言 (REXX 除外) 中,主变量的声明必须在源程序中的 DECLARE CURSOR 语句之前。 在 REXX 中,必须使用参数标记来代替变量,并且必须准备语句。

语句名
游标的 SELECT 语句是打开游标时由 statement-name 标识的预编译 select-statementstatement-name 不得与源程序的另一个 DECLARE CURSOR 语句中指定的 statement-name 相同。 请参阅 PREPARE 以获取预编译语句的说明。

注意

DECLARE CURSOR 的位置: DECLARE CURSOR 语句必须位于所有通过名称明确引用游标的语句之前,C 和 PL/I 除外。

游标的结果表: 处于打开状态的游标指定 结果表 以及相对于该表的行的位置。 该表是由游标的 SELECT 语句指定的结果表。

如果满足以下所有条件,那么游标 可删除 :

  • 外部全查询仅标识一个非目录表或视图且不在嵌套表表达式中的基本表或可删除视图。
  • 外部全查询不包含 VALUES 子句。
  • 外部全查询不包含 GROUP BY 子句或 HAVING 子句。
  • 外部全查询不包含选择列表中的聚集函数。
  • 外部全查询不包含 UNION , UNION ALL , EXCEPT 或 INTERSECT 运算符。
  • 外部全查询的 select-clause 不包含 DISTINCT 子句。
  • 外部全查询不包含 FOR SYSTEM_TIME 时间段规范。
  • 外部全查询在 FROM 子句中不包含 data-change-table-reference
  • select-statement 不包含 ORDER BY 子句,也不包含 UPDATE 子句,并且未在 DECLARE CURSOR 语句中指定 SENSITIVE
  • select-statement 不包含 FOR READ ONLY 子句。
  • 外部全查询的结果不使用临时表。
  • select-statement 不包含涡旋关键字,或者还指定了 SENSITIVE 关键字或 UPDATE 子句。
  • 除非指定 UPDATE 子句,否则选择列表不包含 DATALINK 列。

如果满足以下所有条件,那么与游标关联的外部全查询的选择列表中的结果列 可更新 :

  • 游标可删除。
  • 结果列仅派生自表的列或视图的可更新列。 即,至少一个结果列不得派生自包含运算符,标量函数,常量或自身派生自此类表达式的列的表达式。

如果游标不可删除,那么该游标为 只读

如果省略 UPDATE 子句,那么只能更改子查询的 SELECT 子句中可更新的列。

如果指定 UPDATE 而不指定列名列表,那么可以在标识此游标的后续定位 UPDATE 语句的赋值子句中显示为目标的列的列表确定如下:
  • 如果指定 WITH EXTENDED 指示符,那么将在全查询的第一个 FROM 子句中标识表或视图的所有列。
  • 否则,只有在全查询的第一个 FROM 子句中标识的表或视图的可更新列。

如果使用列名列表指定 UPDATE ,那么在标识此游标的后续定位 UPDATE 语句中,只能将列名列表中指定的列显示为赋值子句中的目标。

游标的作用域: cursor-name 的作用域是定义它的源程序; 即,提交给预编译器的程序。 因此,游标只能由使用游标声明进行预编译的语句引用。 例如,从另一个单独编译的程序调用的程序不能使用由调用程序打开的游标。

游标名的作用域也限制为包含游标的程序正在其中运行的线程。 例如,如果同一程序在同一作业中的两个单独线程中运行,那么第二个线程不能使用由第一个线程打开的游标。

除非在 CRTSQLxxx 命令上指定了 CLOSQLCSR (*ENDJOB) , CLOSQLCSR (*ENDSQL) 或 CLOSQLCSR (*ENDACTGRP) ,否则只能在程序堆栈中的同一程序实例中引用游标。

  • 如果指定了 CLOSQLCSR (*ENDJOB) ,那么程序堆栈上的任何程序实例都可以引用游标。
  • 如果指定了 CLOSQLCSR (*ENDSQL) ,那么游标可由程序堆栈上的任何程序实例引用,直到程序堆栈上的最后一个 SQL 程序结束为止。
  • 如果指定了 CLOSQLCSR (*ENDACTGRP) ,那么激活组中模块的所有实例都可以引用游标,直到激活组结束为止。

虽然游标的作用域是在其中声明游标的程序,但从该程序创建的每个程序包都包含游标的单独实例,并且在运行时可以存在多个游标。 例如,假定使用 CONNECT (Type 2) 语句的程序按以下顺序连接到位置 X 和位置 Y:

EXEC SQL DECLARE C CURSOR FOR…
EXEC SQL CONNECT TO X;
EXEC SQL OPEN C;
EXEC SQL FETCH C INTO…
EXEC SQL CONNECT TO Y;
EXEC SQL OPEN C;
EXEC SQL FETCH C INTO

第二个 OPEN C 语句不会导致错误,因为它引用了另一个游标 C 实例。

SELECT 语句在打开游标时求值。 如果打开,关闭,然后再次打开同一个游标,那么结果可能不同。 如果游标的 SELECT 语句包含 CURRENT DATE , CURRENT TIME 或 CURRENT TIMESTAMP ,那么对这些专用寄存器的所有引用将在每个 FETCH 上生成相同的相应日期时间值。 该值是在打开游标时确定的。 可以同时打开使用同一 SELECT 语句的多个游标。 它们都被认为是独立的活动。

使用序列表达式: 有关将 NEXT VALUE 和 PREVIOUS VALUE 表达式与游标配合使用的信息,请参阅 将序列表达式与游标配合使用

数据分块: 为了更有效地处理数据,数据库管理器可以对只读游标分块数据。 如果游标不会在定位 UPDATE 或 DELETE 语句中使用,那么应将其声明为 FOR READ ONLY。

REXX 中的用法: 如果在 REXX 过程中的 DECLARE CURSOR 语句上使用了变量,那么 DECLARE CURSOR 必须是 PREPARE 和 EXECUTE 的对象。

临时结果: 某些 SELECT 语句 可作为临时结果表实现。

  • 在以下情况下创建临时结果表:
    • 指定了 INSENSITIVE
    • ORDER BY 和 GROUP BY 子句以不同的顺序指定不同的列或列。
    • ORDER BY 和 GROUP BY 子句包含用户定义的函数或下列其中一个标量函数 :DLVALUE , DLPATH , DLPATHONLY , DLSERVER , DLSCHEME 或 DLCOMPLETE for DataLinks ,其属性为 FILE LINK CONTROL 和 READ PERMISSION DB。
    • 指定了 UNION , EXCEPT , INTERSECT 或 DISTINCT 子句。
    • ORDER BY 或 GROUP BY 子句指定并非全部来自同一表的列。
    • 由 JOINDFT 数据定义规范 (DDS) 关键字定义的逻辑文件被连接到另一个文件。
    • 指定了基于多个数据库文件成员的逻辑文件。
    • 当 DECLARE CURSOR 的 SELECT 语句包含 GROUP BY 子句时,会在 FETCH 语句上指定 CURRENT 或 RELATIVE 滚动选项。
    • 指定了 FETCH FIRST n ROWS ONLY 子句。
  • 包含子查询的查询,其中:
    • 最外面的查询未提供任何内部子查询的相关值。
    • 最外层查询不引用 IN、= ANY、= SOME 或 <> ALL 子查询。
游标灵敏度: 具有 OFFSET 和/或 FETCH FIRST 子句的可滚动敏感游标可能会在指定偏移量之前或指定行数之后返回行,如果:
  • 在通过游标访存数据时,将对游标的底层表执行更新,删除或插入操作,并且
  • 针对游标的访存操作尝试返回先前由游标访存的相同行。

语法替代方法: 以下关键字是支持与先前发行版兼容的同义词。 这些关键字是非标准的,不应使用:

  • 动态滚动是敏感动态滚动的同义词

示例

示例 1: 声明 C1 作为查询的游标,以从表 DEPARTMENT 检索数据。 查询本身出现在 DECLARE CURSOR 语句中。

  EXEC SQL DECLARE C1 CURSOR FOR
              SELECT DEPTNO, DEPTNAME, MGRNO
                FROM DEPARTMENT
                WHERE ADMRDEPT = 'A00';

示例 2: 声明 C1 作为查询的游标,以从表 DEPARTMENT 检索数据。 假定稍后将使用搜索的更新来更新数据,并且应该在执行查询时锁定这些数据。 查询本身出现在 DECLARE CURSOR 语句中。

  EXEC SQL DECLARE C1 CURSOR FOR
              SELECT DEPTNO, DEPTNAME, MGRNO
                FROM DEPARTMENT
                WHERE ADMRDEPT = 'A00'
                FOR READ ONLY WITH RS USE AND KEEP EXCLUSIVE LOCKS;

示例 3: 声明 C2 作为名为 STMT2的语句的游标。

  EXEC SQL DECLARE C2 CURSOR FOR STMT2;

示例 4: 声明 C3 作为要在表 EMPLOYEE 的定位更新中使用的查询的游标。 允许不时落实已完成的更新,而不关闭游标。

  EXEC SQL DECLARE C3 CURSOR WITH HOLD FOR
              SELECT *
                FROM EMPLOYEE
                FOR UPDATE OF WORKDEPT, PHONENO, JOB, EDLEVEL, SALARY;

可以使用 UPDATE 子句而不命名这些列,而不是显式指定要更新的列。 这将允许更新表的所有可更新列。 由于此游标是可更新的,因此它还可用于从表中删除行。

示例 5: 在 C 程序中,使用游标 C1 一次从 EMPPROJACT 表的前四列中访存给定项目 (PROJNO) 的值一行,并将它们放入以下主变量中 :EMP (CHAR (6)) , PRJ (CHAR (6)) , ACT (SMALLINT) 和 TIM (DECIMAL (5, 2))。 从主变量 SEARCH_PRJ (CHAR (6)) 获取要搜索的项目的值。 动态准备 select-statement ,以允许在执行程序时指定要搜索的项目。

void main ()
  {
    EXEC SQL  BEGIN DECLARE SECTION;
    char           EMP[7];
    char           PRJ[7];
    char           SEARCH_PRJ[7];
    short          ACT;
    double         TIM;
    char           SELECT_STMT[201];
    EXEC SQL  END DECLARE SECTION;
    EXEC SQL  INCLUDE SQLCA;

    strcpy(SELECT_STMT, "SELECT EMPNO, PROJNO, ACTNO, EMPTIME \
                   FROM EMPPROJACT \
                   WHERE PROJNO = ?");
    .
    .
    .
    EXEC SQL PREPARE SELECT_PRJ FROM :SELECT_STMT;

    EXEC SQL DECLARE C1 CURSOR FOR SELECT_PRJ;

/* Obtain the value for SEARCH_PRJ from the user.     */
    .
    .
    .
    EXEC SQL OPEN C1 USING :SEARCH_PRJ;

    EXEC SQL  FETCH C1 INTO :EMP, :PRJ, :ACT, :TIM;

    if (strcmp(SQLSTATE, "02000", 5) ) 
      {
        data_not_found(); 
      } 
    else 
      {
        while (strcmp(SQLSTATE, "00", 2) || strcmp(SQLSTATE, "01", 2) ) 
          {
            EXEC SQL  FETCH C1 INTO :EMP, :PRJ, :ACT, :TIM;
          }
      }

    EXEC SQL  CLOSE C1;
    .
    .
    .
  }
示例 6: DECLARE CURSOR 语句将游标名 C1 与 SELECT 的结果相关联。 C1 是可更新的可滚动游标。
   EXEC SQL DECLARE C1 SENSITIVE SCROLL CURSOR FOR
       SELECT DEPTNO, DEPTNAME, MGRNO
       FROM TDEPT
       WHERE ADMRDEPT = 'A00';

示例 7: 声明游标以从四列访存值,并使用 Serializable (RR) 隔离级别将值分配给变量:

   EXEC SQL DECLARE CURSOR1 CURSOR FOR
     SELECT COL1, COL2, COL3, COL4
     FROM TBLNAME WHERE COL1 = :varname
     WITH RR;

示例 8: 假定已变更 EMPLOYEE 表以添加生成的列 WEEKLYPAY ,该列根据年薪计算每周薪酬。 声明游标以从要插入的行中检索系统生成的列值。

   EXEC SQL DECLARE C2 CURSOR FOR
     SELECT E.WEEKLYPAY
     FROM FINAL TABLE 
       (INSERT INTO EMPLOYEE
           (EMPNO, FIRSTNME, MIDINIT, LASTNAME, EDLEVEL, SALARY)
           VALUES('000420', 'Peter', 'U', 'Bender', 16, 31842)) AS E;