稍后如何定义游标?

How to define a cursor later?

Oracle Docs中提到游标有两部分,声明和定义。

You can either declare it first (with cursor_declaration) and then define it later in the same block, subprogram, or package (with cursor_definition) or declare and define it at the same time (with cursor_definition).

我已经看过但没能找到显示游标如何在稍后定义的代码示例。

我想声明三个游标,但只在进行时定义它们。例如,游标 1 将删除游标 2 需要执行的工作。我有来自不同系统的数据,它们可以通过三种方式之一进行匹配。一旦匹配,它们就不需要再次匹配,因此其他匹配游标不需要那些如果在开始时就定义它们会获得的值。

这是我期望的样子,但可能是错误的

DECLARE
    CURSOR X IS ...; --cursor declaration and definition
    CURSOR Y; --cursor declaration
    CURSOR Z; --cursor declaration
BEGIN
    FOR i IN X LOOP
        --DO STUFF
    END LOOP;
    Y IS ...; --cursor definition
    FOR ii IN Y LOOP
        --DO STUFF
    END LOOP;
    Z IS ...; --cursor definition
    FOR iii IN Z LOOP
        --DO STUFF
    END LOOP;
END;

还有一些相关的问题

我必须承认我从未想过或尝试过 "deferring" 光标在单个块中的定义。但他们肯定正确地告知您可以在包规范中定义游标声明,并在主体中定义 "hide" 定义。

这是一个例子:

CREATE PACKAGE species_pkg 
IS 
   CURSOR species_cur 
      RETURN endangered_species%ROWTYPE; 
END;
/

CREATE PACKAGE BODY species_pkg 
IS 
   CURSOR species_cur 
      RETURN endangered_species%ROWTYPE 
   IS 
        SELECT * 
          FROM endangered_species 
      ORDER BY common_name; 
END;
/

你可以用我的LiveSQL script试试看。

但我真的不认为这就是您想要执行的解决方案。相反,我会使用游标变量,正如 Mick Mnemonic 在他的回答中向您展示的那样。

将游标声明与其定义分开的主要优点是允许您遵循神圣的 "information hiding" 原则。理论上,开发人员不需要知道查询的实现,只需要知道返回的数据集的描述。

听起来你想要一个 REF CURSOR:

DECLARE
    CURSOR X IS SELECT stuff FROM mytable; --cursor declaration and definition

    TYPE cursor_type IS REF CURSOR;
    cursor_y cursor_type; --cursor declaration
    cursor_z cursor_type; --cursor declaration

    query_string VARCHAR2(200) := 'SELECT stuff FROM anothertable WHERE id=:b1';
BEGIN
    FOR i IN X LOOP
        --DO STUFF
    END LOOP;

    OPEN cursor_y FOR query_string USING my_bind_variable1;
    --cursor definition using dynamic SQL and a bind variable

    FOR ii IN Y LOOP
        --DO STUFF
    END LOOP;

    OPEN cursor_z FOR SELECT stuff FROM anothertable2; --cursor definition

    FOR iii IN Z LOOP
        --DO STUFF
    END LOOP;
END;