как динамически определять типы в plsql

#sql #oracle #plsql

#sql #Oracle #plsql

Вопрос:

У меня есть процедура, подобная этой:

 create or replace procedure pname (tn varchar2) is
-- here i want to declare the variable

  col1 tn%COL_ID

begin

end;
  

и я знаю, что каждая таблица, которую я передаю в качестве аргумента, будет содержать столбец с именем COL_ID. Но я не могу этого сделать, я получаю ошибку, подобную этой

PLS-00487: недопустимая ссылка на переменную ‘tn’ PL / SQL: элемент проигнорирован PLS-00487: Недопустимая ссылка на переменную ‘tn’ PL / SQL: элемент проигнорирован

Пожалуйста, помогите мне в том, как объявлять переменные подобным образом.

Ответ №1:

Интересный вопрос. Как отметил APC, Oracle не имеет отражения для каждого высказывания, как в других языках, поэтому передача имени (varchar2) не сильно помогает Oracle (особенно во время компиляции). Я полагаю, вы хотите сказать, что у вас есть набор таблиц, которые все имеют определенные характеристики (1 или более столбцов одного типа, используемых одинаковым образом), поэтому вы хотите создать универсальную функцию, которая будет работать для любой из них.

Вы можете это сделать, но вам придется определить тип объекта, который определяет общие столбцы и типы, совместно используемые в ваших различных таблицах. Допустим, это следующие 2 столбца:

 create or replace type my_obj as object (name varchar2(100), num number);
  

Теперь ваша функция (или процедура) будет принимать этот тип в качестве параметра:

 create or replace function my_fn(obj my_obj) return varchar2 is
  begin
    -- do something with object
    return obj.name || ',' || obj.num;
  end;
  

И вы бы назвали это как:

 declare
    obj my_obj;
    rv varchar2(1000);
  begin
    for rec in (select * from sometable)
    loop
      obj := my_obj(rec.some_varchar_col, rec.some_number_col);
      select my_fn(obj) into rv from dual;
      dbms_output.put_line(rv);
    end loop;
  end;
  

Единственный другой способ, который я могу придумать, — это принять слабо типизированный sys_refcursor, а затем заставить вызывающие процедуры отправлять правильный курсор (рискованно из-за потенциальных исключений во время выполнения и не очень понятно). Я предпочитаю описанный выше подход при написании «универсальной» функции.

Для полноты редактирования я добавлю пример sys_refcursor, о котором я упоминал выше:

 create or replace procedure my_proc(cur sys_refcursor) is
  v_name varchar2(100);
  v_num number;
begin
  loop
    fetch cur into v_name, v_num;
    exit when cur%notfound;

    -- do something with our common fields
    dbms_output.put_line(v_name || ',' || v_num);
  end loop;
end;
  

И назовите это как:

 declare
  v_cur sys_refcursor;
begin
  open v_cur for select my_name, my_num from some_table;
  my_proc(v_cur);
  close v_cur;
end;
  

ПРИМЕЧАНИЕ
Это кажется слишком тривиальным, имея всего 2 столбца (почему бы просто не задать параметры как varchar2 и number), но у вас могут быть десятки столбцов, с которыми вы хотите поработать в функции, и входной объект может иметь любое их количество заполненных.

Приветствия

Ответ №2:

Синтаксис такой:

 declare
    col1  t23.col1%type;
begin
    null;
end;
/ 
  

Набор документации Oracle находится в Сети. Найдите это здесь. Информация о %TYPE содержится в Руководстве пользователя PL / SQL.


» В вашем примере t23 — это таблица. Не параметр с именем таблицы.»

Справедливое замечание. Я предполагал, что каждое объявление COL1 было одним и тем же типом данных, следовательно, объявление его с использованием одного фиксированного имени таблицы будет работать для всех таблиц. Если это не так, то я согласен, что мое решение не будет работать.

Проблема с передачей имени таблицы обычная: PL / SQL это не поддерживает. Это не имеет ничего похожего на отражение в Java.

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

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

1. 1 Но я не уверен, что это то, о чем спрашивает OP. В вашем примере t23 — это таблица. Не параметр с именем таблицы.

2. У меня нет доступа к командам создания таблицы. Но я думаю, было бы разумно предпочесть динамическое использование типа столбца вместо работы с varchar2. (Даже если его использование памяти оптимизировано и будет занимать только фактически используемое пространство). Информация о %TYPE содержится в Руководстве пользователя PL / SQL .

Ответ №3:

Взгляните на все типы данных, используемые COL_ID во всех таблицах, которые вы могли бы передать процедуре. Скорее всего, все они могут поместиться в один из базовых типов данных — т.е. NUMBER , VARCHAR2(4000) .

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