2013-03-01 3 views
2

Может кто-нибудь сказать мне, что не так с этим кодом. Моя цель - написать процедуру, которая передается имени сотрудника, загружает все имена и зарплаты из таблицы сотрудников в файл VARRAY, а затем печатает имена и зарплаты на экране.pl/sql varray с курсором

CREATE OR REPLACE PROCEDURE VARRAY_Q2 
(
    PNAME IN VARCHAR2 
, PSAL OUT NUMBER 
) AS 

--declare and create cursor 

CURSOR emp_cur IS 
SELECT ename,sal 
FROM EMP; 

    TYPE varray_emp IS VARRAY(14) OF emp_Cur%ROWTYPE; 

    --Creating new instance of varray 
    x_varray_emp varray_emp := varray_emp(); 
    v_counter NUMBER := 0; 

BEGIN 

    x_varray_emp.EXTEND; 

    FOR empRecs IN emp_Cur LOOP 

    --Insert data into the varray 
    x_varray_emp(v_counter) := empRecs; 

    dbms_output.put_line(v_counter); 

    v_counter := v_counter + 1; 
    END LOOP; 

    --Loop through the varray and print out all the elements 
    FOR i IN x_varray_emp.FIRST .. x_varray_emp.LAST 
    LOOP 
    dbms_output.put_line(x_varray_emp(i));  
    END LOOP; 

END; 
+0

1. Почему вы передаете какие-либо параметры в процедуру, если они не используются? 2. Зачем беспокоиться о VARRAY, когда вы можете сделать свою операцию прямо в цикле курсора? 3. Если вы не видите вывод, вы, вероятно, хотите «установить serveroutput on». – Glenn

+0

Какая ошибка вы получаете? – Allan

+0

@Glenn Я думаю, он учится, как это сделать, и будет использовать параметры и varray после того, как он выберет эту часть. –

ответ

9

Во-первых: PL/SQL Коллекции не основаны на 0. Это вызовет ошибку индексации из-за пределов, потому что ваш счетчик смотрел на 0. Вам также не нужен счетчик для этого решения. Если вы хотите продолжить использовать его, см. Первый пример. Но если бы я был вами, я бы использовал второй пример.

Во-вторых, вы расширили varray перед циклом. Это приведет к выкидыванию индекса за пределы ошибки подсчета, потому что varray был расширен только для того, чтобы удерживать одну строку. Вам нужно расширить его в начале цикла, чтобы на каждой итерации расширялся.

Thid, вы не можете PUT_LINE целый рюкзак. У вас должно быть put_line элементов в varray. Таким образом, в этом примере, а не dbms_output.put_line(x_varray_emp(i)) использовать вместо этого: dbms_output.put_line(x_varray_emp(i).ename || ' makes $' || x_varray_emp(i).sal)

Четвертое: если таблица EMP имеет более 14 записей в этом, ваш VARRAY(14) вызовет индекс вне предела погрешности. varrays имеют максимальный размер, установленный для них (ограниченный предел), который в вашем случае равен 14. В этом примере я бы использовал обычную вложенную таблицу (TYPE nested_emp IS TABLE OF emp_cur%ROWTYPE), чтобы не беспокоиться о ограниченных пределах (технически, вложенная таблица имеет максимум 2147483647, а также PLS_INTEGER). Если вы хотите использовать NT над VA, используйте вместо этого третье решение.

Сделайте следующее, и оно будет работать.

изменить v_counter NUMBER := 0 на v_counter NUMBER := 1;

Изменить то, что в организме это:

BEGIN 
    FOR empRecs IN emp_Cur LOOP 
     x_varray_emp.EXTEND; 
     --Insert data into the varray 
     x_varray_emp(v_counter) := empRecs; 

     dbms_output.put_line(v_counter); 

     v_counter := v_counter + 1; 
    END LOOP; 
    --Loop through the varray and print out all the elements 
    FOR i IN x_varray_emp.FIRST .. x_varray_emp.LAST LOOP 
     dbms_output.put_line(x_varray_emp(i).ename || ' Makes $' || x_varray_emp(i).sal); 
    END LOOP; 
END; 

Вам не нужен счетчик, на самом деле. Если вы готовы отказаться от него, используйте COUNT метод VARRAY вместо:

BEGIN 


    FOR empRecs IN emp_Cur LOOP 
     x_varray_emp.EXTEND; 

     --Insert data into the varray 
     x_varray_emp(x_varray_emp.count) := empRecs; 

     dbms_output.put_line(x_varray_emp.count); 


    END LOOP; 

    --Loop through the varray and print out all the elements 
    FOR i IN x_varray_emp.FIRST .. x_varray_emp.LAST LOOP 
     dbms_output.put_line(x_varray_emp(i).ename || ' Makes $' || x_varray_emp(i).sal); 
    END LOOP; 


END; 

Я предпочел бы использовать вложенную таблицу для этой задачи над VARRAY. ЕСЛИ вы согласны, вот решение:

DECLARE 

    CURSOR emp_cur IS SELECT ename,sal FROM EMP; 
    TYPE nestedtable_emp IS TABLE OF emp_cur%ROWTYPE; 

    x_nestedtable_emp nestedtable_emp := nestedtable_emp(); 
BEGIN 


    FOR empRecs IN emp_Cur LOOP 
     x_nestedtable_emp.EXTEND; 

     --Insert data into the varray 
     x_nestedtable_emp(x_nestedtable_emp.count) := empRecs; 

     dbms_output.put_line(x_nestedtable_emp.count); 


    END LOOP; 

    --Loop through the varray and print out all the elements 
    FOR i IN x_nestedtable_emp.FIRST .. x_nestedtable_emp.LAST LOOP 
     dbms_output.put_line(x_varray_emp(i).ename || ' Makes $' || x_varray_emp(i).sal); 
    END LOOP; 


END; 
+0

Если мы используем вложенную таблицу, BULK COLLECT будет лучшим подходом. Но эта задача не нуждается в какой-либо коллекции: простой цикл FOR CURSOR - это все, что требуется. Это просто демонстрирует бесполезность таких домашних упражнений: они учат механике языка, но не как правильно его использовать. Таким образом, все ученики на самом деле узнают, как написать плохой PL/SQL. – APC

Смежные вопросы