Почему я не могу использовать переменную связывания в операторе немедленного выполнения? - PullRequest
1 голос
/ 02 августа 2011

Я бы хотел использовать переменные связывания вместо конкатенации строк при создании оператора динамического SQL для execute immediate.

В примере ниже я могу использовать переменные связывания для a, b и ret, но когда я пытаюсь связать для f, я получаю ORA-06502: PL/SQL: numeric or value error: character to number conversion error. Почему и как я могу связать также f?

Я использую 11.2.0.1.0.

create or replace function so4fun (
  a in number, 
  b in number,
  f in varchar2
) return number as
  decl constant varchar2(32767) := 
    'declare a constant number := :a; b constant number := :b;';
  stmt varchar2(32676);
  ret number;
begin
  /* This one works: */
  stmt := decl || ' begin :result := ' || f || '; end;';
  execute immediate stmt using in a, in b, out ret;

  /* But why this one doesn't ?

  stmt := decl || ' begin :result := :f; end;';
  execute immediate stmt using in a, in b, out ret, in f;

  This doesn't work either:

  stmt := decl || ' tmp number; begin tmp := :f; :result := tmp; end;';
  execute immediate stmt using in a, in b, in f, out ret;

  Both are giving me ORA-06502: PL/SQL: numeric or value error: character to
  number conversion error */

  return ret;
end;
/
show errors

/* expected result when a = 1, b = 2 is 1.5 */
select so4fun(1, 2, '(a + b) / b') from dual;

drop function so4fun;

Ответы [ 2 ]

2 голосов
/ 02 августа 2011

Переменные связывания предназначены для связывания переменных, а не для связывания фрагментов кода. Идея состоит в том, что Oracle может компилировать и кэшировать запрос или блок кода и выполнять его несколько раз с различными параметрами.

Однако вы пытаетесь использовать привязку параметров для замены вычисленной формулы. Это предотвратит компиляцию и кеширование блока кода и поэтому не поддерживается.

Кроме того, оно не может быть выражено текущим синтаксисом. Если Oracle видит tmp := :f, он думает, что вы просто хотите присвоить параметр f переменной tmp. Не нужно оценивать функцию.

Просто иди с рабочим решением. Это работает в конце концов.

1 голос
/ 02 августа 2011

Ошибка возникает из-за того, что вы объявили f как varchar2, но вы написали в закомментированном разделе следующее:

tmp number; begin tmp := :f ...

, в котором вы пытаетесь присвоить «символьное» значение переменной, которая ожидает число. Вы также пытались присвоить f результату функции, который снова ожидает число.

С || все работает нормально, потому что это конкатенация строк.

Вам нужно каким-то образом преобразовать ваш varchar2 в число (TO_NUMBER(f)) или, возможно, написать свой процесс, чтобы принять параметр f в виде числа, а не varchar2.

...