Как я могу использовать переменные динамически, изменяя их имена с помощью кода - PullRequest
0 голосов
/ 05 ноября 2019

Требуется способ обращения к различным переменным путем динамического изменения их имен в блоке plsql.

Попытка с простыми циклами, которые изменят эффективные имена переменных. Запись каскадного блока plsql с использованием оператора, но из-за размера существующего кода это бесполезно.

set serveroutput on;
declare
foo1 number:=111;
foo2 number:=222;
begin
execute immediate 'dbms_output.put_line(foo'||'1)';
for i in 0..2
loop
dbms_output.put_line(foo||i);
end loop;
end;
/

ожидаемый вывод будет 111, выводится ошибка, как показано ниже. Отчет об ошибке - ORA-00900: недопустимый оператор SQL ORA-06512: в строке 5 00900. 00000 - «неверный оператор SQL»

Ответы [ 2 ]

4 голосов
/ 05 ноября 2019

Ваши переменные являются локальными. Пакет DBMS_OUTPUT не знает их. Таким образом, результирующая строка dbms_output.put_line(foo1) не может быть выполнена с помощью execute immediate.

. Типичным способом решения этой проблемы является использование массива значений, а не отдельных переменных:

declare
  type t_array is varray(2) of integer;
  v_array t_array := t_array(111, 222);
begin
  for i in 1..2 loop
    dbms_output.put_line(v_array(i));
  end loop;
end;

то же самое с динамическим массивом:

declare
  type t_array is table of integer;
  v_array t_array := t_array();
begin
  v_array.extend(1);
  v_array(1) := 111;
  v_array.extend(1);
  v_array(2) := 222;
  for i in 1 .. v_array.count loop
    dbms_output.put_line(v_array(i));
  end loop;
end;
2 голосов
/ 05 ноября 2019

Давайте сделаем это по одному шагу за раз. Во-первых, статический код, который работает:

SQL> declare
  2  foo1 number:=111;
  3  foo2 number:=222;
  4  begin
  5  dbms_output.put_line(foo1);
  6  end;
  7  /

111

Теперь, если вы хотите ВЫПОЛНИТЬ НЕМЕДЛЕННЫЙ текст, вы должны поместить весь код в текст:

SQL> declare
  2    l_code_block varchar2(4000) := '
  3  declare
  4  foo1 number:=111;
  5  foo2 number:=222;
  6  begin
  7  dbms_output.put_line(foo2);
  8  end;
  9  ';
 10  begin
 11  execute immediate l_code_block;
 12  end;
 13  /

222

Следующий шаг: если мы хотим динамически изменить значение , мы можем и должны использовать «переменную связывания».

SQL> declare
  2    l_code_block varchar2(4000) := '
  3  declare
  4  foo1 number:=111;
  5  foo2 number:=222;
  6  begin
  7  dbms_output.put_line(:n);
  8  end;
  9  ';
 10  begin
 11  execute immediate l_code_block using 1;
 12  end;
 13  /

1

Но если мы попытаемся использовать переменную связываниячтобы изменить код , он не работает.

SQL> declare
  2    l_code_block varchar2(4000) := '
  3  declare
  4  foo1 number:=111;
  5  foo2 number:=222;
  6  begin
  7  dbms_output.put_line(foo:n);
  8  end;
  9  ';
 10  begin
 11  execute immediate l_code_block using 1;
 12  end;
 13  /

...
Error report -
ORA-06550: line 6, column 25:
PLS-00103: Encountered the symbol "" when expecting one of the following
...

Поэтому, если мы хотим динамически изменить код , мы должны выполнить ЗАМЕНУ натекст.

SQL> declare
  2    l_code_block varchar2(4000) := '
  3  declare
  4  foo1 number:=111;
  5  foo2 number:=222;
  6  begin
  7  dbms_output.put_line(foo#N#);
  8  end;
  9  ';
 10  begin
 11  execute immediate replace(l_code_block,'#N#',1);
 12  end;
 13  /

111

Наконец, вот ваш цикл:

SQL> declare
  2    l_code_block varchar2(4000) := '
  3  declare
  4  foo1 number:=111;
  5  foo2 number:=222;
  6  begin
  7  dbms_output.put_line(foo#N#);
  8  end;
  9  ';
 10  begin
 11    for i in 1..2 loop
 12      execute immediate replace(l_code_block,'#N#',i);
 13    end loop;
 14  end;
 15  /

111
222

Пожалуйста, поймите, я пытаюсь ответить на ваш вопрос в том виде, в котором он был задан. Этого «динамического» подхода следует избегать всякий раз, когда это возможно, и это почти всегда возможно. Мы должны были бы вернуться к бизнес-требованиям, чтобы рекомендовать наиболее подходящую технику.

С уважением, Стью Эштон

...