PL / SQL: я получаю «Идентификатор j должен быть объявлен», когда я пытаюсь вызвать sql%bulk_rowcount (j);

#oracle #plsql

#Oracle #plsql

Вопрос:

Мой код:

 create table dep_emp_ast(
cod_dep number(3),
cod_ang number(3));

declare
type tab_imb is table of dept_ast.department_id%type;
type ang is table of emp_ast.employee_id%type;
v_ang ang:=ang();
t tab_imb:=tab_imb();
begin
select department_id
bulk collect into t
from dept_ast;

for i in 1..t.count loop
select employee_id bulk collect into v_ang
from emp_ast
where department_id=t(i);

forall j in 1..v_ang.count
insert into dep_emp_ast
values(t(i), v_ang(j));
dbms_output.put_line( sql%bulk_rowcount(j));
v_ang.delete;
end loop;
end;
/
  

Я получаю «Идентификатор ‘j’ должен быть объявлен»» при попытке вызвать sql%bulk_rowcount (j);
Я знаю, что могу использовать sql%bulk_rowcount (index) в циклах for или forall .

Комментарии:

1. Вы нигде не объявили j .

Ответ №1:

Вот рабочая версия.

Я переименовал некоторые переменные, чтобы их было легче понять (по крайней мере, для меня), и добавил еще несколько dbms_output сообщений, чтобы более четко показать, что он делает.

 declare
    type tab_dept is table of dept_ast.department_id%type;
    type tab_emp  is table of emp_ast.employee_id%type;
    employees_t    tab_emp := tab_emp();
    departments_t  tab_dept := tab_dept();
begin
    select department_id bulk collect into departments_t
    from   dept_ast;

    dbms_output.put_line(departments_t.count || ' departments added to departments_t');

    for i in 1 .. departments_t.count loop
        select employee_id bulk collect into employees_t
        from   emp_ast where department_id = departments_t(i);

        dbms_output.put_line(employees_t.count || ' employees added to employees_t for department_id '||departments_t(i));

        forall j in 1 .. employees_t.count
        insert into dep_emp_ast
        values
        ( departments_t(i)
        , employees_t(j) );

        for k in 1 .. employees_t.count loop
            dbms_output.put_line('sql%bulk_rowcount('||k||') = '|| sql%bulk_rowcount(k));
        end loop;

        dbms_output.put_line('sql%rowcount = ' ||sql%rowcount);
        employees_t.delete;
    end loop;
end;
  

Вывод:

 3 departments added to departments_t
2 employees added to employees_t for department_id 1
sql%bulk_rowcount(1) = 1
sql%bulk_rowcount(2) = 1
sql%rowcount = 2
2 employees added to employees_t for department_id 2
sql%bulk_rowcount(1) = 1
sql%bulk_rowcount(2) = 1
sql%rowcount = 2
2 employees added to employees_t for department_id 3
sql%bulk_rowcount(1) = 1
sql%bulk_rowcount(2) = 1
sql%rowcount = 2
  

Тестовая настройка:

 create table dep_emp_ast(
cod_dep number(3),
cod_ang number(3));

create table dept_ast
( department_id number );

create table emp_ast
( employee_id number 
, department_id number );

delete dept_ast;
delete emp_ast;

insert all
    into dept_ast values (1)
    into dept_ast values (2)
    into dept_ast values (3)
    into emp_ast (department_id, employee_id) values (1, 10)
    into emp_ast (department_id, employee_id) values (1, 20)
    into emp_ast (department_id, employee_id) values (2, 30)
    into emp_ast (department_id, employee_id) values (2, 40)
    into emp_ast (department_id, employee_id) values (3, 50)
    into emp_ast (department_id, employee_id) values (3, 60)
select * from dual;
  

Ответ №2:

@WilliamRobertson прав в своем комментарии, что «вы нигде не объявили j», и я верю ему на слово, что это рабочая версия. Но ни то, ни другое на самом деле не объясняет, почему вы получаете ошибку. Ваш код на самом деле показывает 2 заблуждения.
Сначала инициализация (из-за отсутствия лучшей работы) FOR и FORALL

 FOR <index> IN <lower bound> .. <upperbound> Loop ... END LOOP; 
FORALL <index> IN <lower bound> .. <upperbound> DML statement;
  

В обоих случаях переменная создается только на время действия инструкции. Таким образом, когда цикл или оператор DML завершается, переменная больше не существует. Таким образом, когда вы использовали переменную j после завершения вставки, она больше не существовала. Даже если вы объявляете переменную с тем же именем, правила определения области действия делают их разными переменными (см. Пример здесь).
У вас есть и другая проблема. SQL%bulk_rowcount содержит запись as для каждой обработанной строки строки, но поскольку индексная переменная forall больше не существует, вам нужен цикл FOR для их итерации. Итак, после forall:

 for j in 1..v_ang.count
loop
    dbms_output.put_line( ' Rows for ' || v_ang(j) || ':' || SQL%bulk_rowcount(j));
end loop;
  

Но предполагая, что v_ang содержит таблицу PK для employee (кажется вероятным), которая просто предоставит вам список из 1. Возможно, вам действительно нужен SQL%Rowcount . Это дает вам общее количество обработанных строк.

Я надеюсь, это поможет вам понять для (всех) переменных индекса цикла.