Как инициализировать коллекцию вложенных таблиц, которая находится внутри записи PL / SQL? - PullRequest
1 голос
/ 17 января 2011

Друзья,

Надеюсь, вы можете помочь.

То, чего я пытаюсь добиться, - это использовать типы коллекций, к которым можно обращаться как внутри, так и снаружи PL / SQL, чтобы внешняя программа могла объявить тип этой коллекции и работать с ее содержимым.

Коллекция будет содержать несколько скейлеров и один составной тип данных.

Используя в качестве примера схему Скотта, цель состоит в том, чтобы каждая запись в коллекции содержала информацию об отделе, а в одной записи - коллекцию, содержащую информацию о сотрудниках для этого отдела.

У меня есть выходные данные, которые мне требуются при использовании ассоциативных массивов PL / SQL, но они могут использоваться только с PL / SQL.

Когда я преобразовываю код для использования другого типа коллекции, вложенной таблицы, я получаю ORA-06531: Reference to uninitialized collection, потому что я не инициализировал коллекцию, содержащуюся в записи.

Можно ли добиться этого с помощью этой конструкции? Или (как я все больше чувствую!) Я пошел по неверному пути?

Далее следуют два примера кода.

Во-первых, тот, который работает с ассоциативными массивами PL / SQL:

DECLARE

   TYPE emp_tab_type IS TABLE OF emp%ROWTYPE
        INDEX BY BINARY_INTEGER;

    TYPE dept_emp_rec IS RECORD (dept_id    dept.deptno%TYPE,
                                 dept_name    dept.dname%TYPE,
                                 dept_loc    dept.loc%TYPE,    
                                 emp_data   emp_tab_type);  

    TYPE dept_emp_tab_type IS TABLE OF dept_emp_rec
        INDEX BY BINARY_INTEGER;

    l_dept_emp_tab    dept_emp_tab_type;

    CURSOR dept_cur IS
        SELECT d.*
        FROM dept d
        ORDER BY  d.deptno;

    CURSOR emps_cur (p_dept_id IN NUMBER ) IS 
        SELECT e.*
        FROM emp e
        WHERE e.deptno = p_dept_id
        ORDER BY e.ename;

    j   PLS_INTEGER := 1;

    k   PLS_INTEGER;

BEGIN


    FOR dept_rec IN dept_cur 
    LOOP

       -- populate dept data
       l_dept_emp_tab(j).dept_id := dept_rec.deptno;

       -- other assignment statements

       dbms_output.put_line('dept no ' ||   l_dept_emp_tab(j).dept_id);

       -- populate emp data
       k := 1;             

       FOR emp_row_rec IN emps_cur(dept_rec.deptno)
       LOOP

           l_dept_emp_tab(j).emp_data(k).empno := emp_row_rec.empno;

           -- other assignment statements

           dbms_output.put_line( l_dept_emp_tab(j).emp_data(k).empno);

           k := k + 1;

       END LOOP;

       j := j + 1;

    END LOOP;


END;

Это пример использования вложенных таблиц, которые НЕ РАБОТАЮТ

DECLARE

   TYPE emp_tab_type IS TABLE OF emp%ROWTYPE;
        --INDEX BY BINARY_INTEGER;

    TYPE dept_emp_rec IS RECORD (dept_id    dept.deptno%TYPE,
                                 dept_name    dept.dname%TYPE,
                                 dept_loc    dept.loc%TYPE,    
                                 emp_data   emp_tab_type);  

    TYPE dept_emp_tab_type IS TABLE OF dept_emp_rec;
        --INDEX BY BINARY_INTEGER;

    l_dept_emp_tab    dept_emp_tab_type := dept_emp_tab_type(); 

    CURSOR dept_cur IS
        SELECT d.*
        FROM dept d
        ORDER BY  d.deptno;

    CURSOR emps_cur (p_dept_id IN NUMBER ) IS 
        SELECT e.*
        FROM emp e
        WHERE e.deptno = p_dept_id
        ORDER BY e.ename;

    j   PLS_INTEGER := 1;

    k   PLS_INTEGER;

BEGIN


    FOR dept_rec IN dept_cur 
    LOOP

      l_dept_emp_tab.EXTEND;

       -- populate dept data
       l_dept_emp_tab(j).dept_id := dept_rec.deptno;

       -- other assignment statements

       dbms_output.put_line('dept no ' ||   l_dept_emp_tab(j).dept_id);

       -- populate emp data
       k := 1;             

       FOR emp_row_rec IN emps_cur(dept_rec.deptno)
       LOOP

           l_dept_emp_tab(j).emp_data(k).empno := emp_row_rec.empno;

           -- other assignment statements

           dbms_output.put_line( l_dept_emp_tab(j).emp_data(k).empno);

           k := k + 1;

       END LOOP;

       j := j + 1;

    END LOOP;


END;

Я использую Oracle Enterprise Edition 10.2.0.4

Спасибо

Ответы [ 2 ]

3 голосов
/ 18 января 2011

Вы действительно получаете ошибку ORA-06531, потому что вы не инициализировали коллекции в каждой записи. Для этого попробуйте добавить строку

       l_dept_emp_tab(j).emp_data := emp_tab_type();

для других назначений для полей l_dept_emp_tab(j).

Вам также необходимо добавить вызов к l_dept_emp_tab(j).emp_data.EXTEND во внутреннем цикле, чтобы освободить место для новой записи, которая будет добавлена. Вставьте это выше всех назначений во внутреннем цикле. Если вы не добавите это, вы получите ошибку ORA-06533: Subscript beyond count.

Кажется, вы правильно обрабатываете внешний тип вложенной таблицы (dept_emp_tab_type), вызывая ее конструктор (в разделе DECLARE) и вызывая EXTEND для увеличения вложенной таблицы. Все, что вам нужно сделать, это сделать то же самое для каждого экземпляра типа внутренней вложенной таблицы, emp_tab_type.

2 голосов
/ 18 января 2011

Это другой способ, он выполняет почти все в запросе (обратите внимание, что для этого необходимо, чтобы типы создавались вне блока)

http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

Создание и очистка таблицы и используемых типов

/*
CREATE  TABLE EMP (ENAME VARCHAR2(50) , DEPTNO NUMBER, empno number);
INSERT INTO EMP VALUES('m1e',1,1);
INSERT INTO EMP VALUES('m2e',1,2);
insert into emp values('m3e',2,3);
INSERT INTO EMP VALUES('m2e',2,4);
insert into emp values('m3e',3,5);

CREATE TABLE DEPT(deptno NUMBER, dname VARCHAR2(50), loc VARCHAR2(50));
INSERT INTO DEPT VALUES(1 ,'portland','tt');
INSERT INTO DEPT VALUES(2 ,'astoria','tt');
INSERT INTO DEPT VALUES(3 ,'eugene','tt');

Создание типов (обратите внимание, что это не входит в пакет / блок, чтобы он был доступен для SQL)

---
drop type emptable force;
DROP TYPE EMP_TAB_TYPE force;
drop type emptable ;
DROP TYPE DEPT_EMP_REC force;
drop type dep_emp_rec_table force;
DROP TABLE DEPT;
drop table emp;

*/

Теперь создайте типы вне пакета / блока, чтобы типы были доступны для SQL

create or replace  TYPE emp_tab_type as object (ENAME VARCHAR2(50) , DEPTNO NUMBER);
create or replace type emptable as table of emp_tab_type ;
    CREATE OR REPLACE  TYPE DEPT_EMP_REC AS OBJECT (
                                 DEPT_ID    NUMBER,
                                 dept_name    varchar2(50),
                                 dept_loc    varchar2(50),    
                                 emp_data   emptable);  
create or replace type dep_emp_rec_table as table of dept_emp_rec;

Теперь мы можем напрямую выбирать типы в запросе (обратите внимание на использование cast / MULTISET )

SELECT 
                  DEPT_EMP_REC(
                                deptno, 
                                dname , 
                                loc , 
                         CAST(MULTISET(SELECT ENAME, DEPTNO
                                         FROM EMP e
                                         WHERE e.DEPTNO = d.deptno)
                              AS emptable))
  FROM DEPT D ;
/
DEPT_EMP_REC(DEPTNO,DNAME,LOC,CAST(MULTISET(SELECTENAME,DEPTNOFROMEMPEWHEREE.DEPTNO=D.DEPTNO)ASEMPTABLE))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              DEPT_EMP_REC(1,'portland','tt',EMPTABLE(EMP_TAB_TYPE('m1e',1),EMP_TAB_TYPE('m2e',1)))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
DEPT_EMP_REC(2,'astoria','tt',EMPTABLE(EMP_TAB_TYPE('m3e',2),EMP_TAB_TYPE('m2e',2)))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
DEPT_EMP_REC(3,'eugene','tt',EMPTABLE(EMP_TAB_TYPE('m3e',3))) 

Теперь блок немного проще (собрать все вместе)

set serveroutput on
DECLARE


p_dep_emp_rec_table dep_emp_rec_table;

BEGIN
     SELECT
        DEPT_EMP_REC( 
           DEPTNO, 
           DNAME, 
           LOC, 
           CAST( MULTISET
                   (   
                    SELECT 
                            ENAME, 
                            DEPTNO 
                       FROM EMP E 
                      WHERE E.DEPTNO = D.DEPTNO
                ) AS EMPTABLE ) 
            )
      BULK COLLECT INTO p_dep_emp_rec_table
       FROM
        DEPT d ;


   FOR I IN P_DEP_EMP_REC_TABLE.FIRST..P_DEP_EMP_REC_TABLE.LAST LOOP
      DBMS_OUTPUT.PUT_LINE(I || ':' || P_DEP_EMP_REC_TABLE(I).DEPT_ID || '|' || P_DEP_EMP_REC_TABLE(I).DEPT_NAME || '|' ||  P_DEP_EMP_REC_TABLE(I).DEPT_LOC);
      DBMS_OUTPUT.PUT_LINE('-----------------------');
      FOR J IN P_DEP_EMP_REC_TABLE(I).EMP_DATA.FIRST..P_DEP_EMP_REC_TABLE(I).EMP_DATA.LAST LOOP
        NULL;
        dbms_output.put_line(P_DEP_EMP_REC_TABLE(i).emp_data(j).ENAME || '/' || P_DEP_EMP_REC_TABLE(i).emp_data(j).DEPTNO);
      end loop;
   END LOOP;
END;


anonymous block completed
1:1|portland|tt
-----------------------
m1e/1
m2e/1
2:2|astoria|tt
-----------------------
m3e/2
m2e/2
3:3|eugene|tt
-----------------------
m3e/3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...