【问题标题】:Nested Cursors in PL/SQLPL/SQL 中的嵌套游标
【发布时间】:2014-04-01 10:33:33
【问题描述】:

我正在使用 Oracle PL/SQL。 我正在尝试定义嵌套游标,这意味着第一个游标的输出应该是第二个游标的输入。更具体地说:第一个应该存储具有特定前缀的表。第二个应该存储第一个中所有表的属性的所有值。

这是我的代码 sn-p。我希望它能让我的问题更清楚一点:

DECLARE
    var_table_name  VARCHAR2(30);
    var_dimension_key  VARCHAR2(30);

CURSOR cur_all_dim IS  
    SELECT 
        table_name
        FROM  dba_tables
        WHERE dba_tables.tablespace_name = 'USERS'
        AND dba_tables.owner = 'DWH_CORE'
        AND UPPER (dba_tables.table_name) LIKE ('%DIM%%')
        AND UPPER (dba_tables.table_name) NOT LIKE ('%TEMP%')
        AND UPPER (dba_tables.table_name) NOT LIKE ('%DEBUG%')
        AND UPPER (dba_tables.table_name) NOT LIKE ('%LOG%');

CURSOR cur_dimension_key IS
    SELECT dimension_key FROM var_table_name;


BEGIN
OPEN cur_all_dim;

LOOP
EXIT WHEN cur_all_dim%NOTFOUND;

    FETCH cur_all_dim INTO var_table_name;

    OPEN cur_dimensions_key;
    LOOP
    EXIT WHEN cur_dimensions_key%NOTFOUND;
    FETCH cur_dimensions_key INTO var_dimension_key;
    dbms_output.put_line (var_table_name);
    dbms_output.put_line (var_dimension_key);


    END LOOP;
    CLOSE cur_dimension_key;
END LOOP;
CLOSE cur_all_dim;
END;

【问题讨论】:

    标签: oracle plsql nested database-cursor


    【解决方案1】:

    静态游标只能访问静态对象。换句话说,静态游标仅在所有表和列在编译时都已知的情况下才起作用。

    如果您需要访问名称仅在执行期间知道的表,则必须使用dynamic SQL。例如,您可以在您的情况下使用REF CURSOR:

    DECLARE
       var_table_name    VARCHAR2(30);
       var_dimension_key VARCHAR2(30);
       cur_dimension_key SYS_REFCURSOR;
    BEGIN
       FOR cur_all_dim IN (SELECT table_name
                             FROM dba_tables
                            WHERE dba_tables.tablespace_name = 'USERS'
                              AND dba_tables.owner = 'DWH_CORE'
                              AND UPPER(dba_tables.table_name) LIKE ('%DIM%%')
                              AND UPPER(dba_tables.table_name) NOT LIKE ('%TEMP%')
                              AND UPPER(dba_tables.table_name) NOT LIKE ('%DEBUG%')
                              AND UPPER(dba_tables.table_name) NOT LIKE ('%LOG%')) 
       LOOP      
          OPEN cur_dimension_key 
           FOR 'SELECT dimention_key 
                  FROM ' || cur_all_dim.table_name;
          LOOP
             FETCH cur_dimensions_key INTO var_dimension_key;
             EXIT WHEN cur_dimensions_key%NOTFOUND;
             dbms_output.put_line(cur_all_dim.table_name);
             dbms_output.put_line(var_dimension_key);      
          END LOOP;
          CLOSE cur_dimension_key;
       END LOOP;
    END;
    

    【讨论】:

    • 谢谢.. 我想我开始明白这应该如何工作了。但是“cur_all_dim”在哪里定义?该定义已在您的代码中消失,但已被使用。所以我得到了它没有声明的错误。
    • 我使用了implicit cursor。游标变量是循环的局部变量,与标准过程 FOR 循环中的方式类似(您无需在 FOR i IN 1..n 中声明 i)。
    • 好的,我明白了。但是为什么我得到一个错误'CUR_DIMENSIONS_KEY'没有声明? (PLS-00201)
    • 可能是因为我的代码中有错字,CUR_DIMENSIONS_KEY 没有声明,但 CUR_DIMENSION_KEY 是!
    • 哦,谢谢.. 我应该亲眼看到的。你帮了我很多!
    【解决方案2】:
        create or replace PROCEDURE PROC_NESTED_CURSOR 
        AS 
        CUR1 SYS_REFCURSOR;
        CUR2 SYS_REFCURSOR;
        LV_DEPTID NUMBER;
        LV_DEPTNAME VARCHAR2(200);
        LV_EMPID NUMBER;
        LV_FSTNAME VARCHAR2(200);
        LV_SALARY NUMBER(8,2);
        LV_JOBID VARCHAR2(20);
        BEGIN
          OPEN CUR1 FOR 
            select department_id, department_name from departments;
    
          LOOP 
            FETCH CUR1 INTO LV_DEPTID,LV_DEPTNAME; 
            EXIT WHEN CUR1%NOTFOUND;    
            dbms_output.put_line('                                                                                                   ');
            dbms_output.put_line('DEPARTMENT ID  '||LV_DEPTID ||'                               '|| 'DEPARTMENT NAME  '||LV_DEPTNAME);
            dbms_output.put_line('---------------------------------------------------------------------------------------------------');
            dbms_output.put_line(RPAD('EMPLOYEE NUMBER',20)||RPAD('EMPLOYEE NAME',20) ||RPAD('SALARY',20)||RPAD('JOB',20) );
              OPEN CUR2 FOR SELECT EMPLOYEE_ID,FIRST_NAME,SALARY,JOB_ID FROM EMPLOYEES WHERE DEPARTMENT_ID = LV_DEPTID;
              LOOP 
                FETCH CUR2 INTO LV_EMPID,LV_FSTNAME,LV_SALARY,LV_JOBID;
                EXIT WHEN CUR2%NOTFOUND;
                 dbms_output.put_line(RPAD( LV_EMPID,20)|| RPAD(LV_FSTNAME,20)||RPAD(LV_SALARY,20)||LV_JOBID);
    
                END LOOP;
           END LOOP; 
        END PROC_NESTED_CURSOR;
    
    /**This will print like this:-
        Department Number :10               Department Name : XXXX
        ________________________________________________________
        EMPLOYEE NUMBER    EMPLOYEE NAME      SALARY         JOB
    
        XXXXXX                  XXXXXX                  XXXX            XXXXX
        XXXXXX                  XXXXXX                  XXXX            XXXXX
        .........
    
    **/
    

    【讨论】:

      猜你喜欢
      • 2020-04-01
      • 2018-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多