2014-02-28 104 views
2

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

这是我的代码片段。我希望它能让我的问题更加清楚:

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; 

回答

7

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

如果您需要访问名称只在执行期间知道的表,则必须使用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; 
+0

谢谢..我想我开始明白这应该是如何工作的。 但是“cur_all_dim”是在哪里定义的?定义已经在你的代码中消失了,但它已经被使用了。所以我得到了它没有被声明的错误。 – user3364656

+0

我已经使用了[隐式游标](http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/static.htm#LNPLS99957)。游标变量对循环来说是本地的,与标准的程序性'FOR'循环类似(你不需要在'FOR IN IN 1..n'中声明'i')。 –

+0

好吧,我明白这一点。但为什么我得到一个错误'CUR_DIMENSIONS_KEY'没有被声明? (PLS-00201) – user3364656

0
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 
    ......... 

**/