Динамический доступ к элементу пользовательских объектов в PL / SQL - PullRequest
0 голосов
/ 27 марта 2009

Есть ли способ получить доступ к динамически доступному члену определенная запись, объект или ссылочный курсор с помощью переменной? Например. Что-то вроде

  get_member(my_object, 'member name');

Или, может быть

  my_object.$'member name';

EXECUTE IMMEDIATE не будет работать, поскольку он не работает в рамках моей процедуры.

Позвольте мне кратко объяснить, что я пытаюсь сделать. У меня есть таблица отображения M, которая описывает, как записи таблицы A должны быть преобразованы в записи таблицы B. Отображение должно варьироваться в зависимости от конкретного типа записи в A (заданной A.type). Я хотел выполнить сопоставление примерно так (не совсем, планируя инкапсуляцию логики сопоставления внутри функции потока, но принцип остается схожим):

SELECT
  ...   
  CASE 
    WHEN M.field_1_mapping IS NOT NULL THEN
      -- column of A given by value of M.field_1_mapping
    ELSE
      null -- field_1 not filled for record type
  END field_1,
  --- etc.
FROM
  table_a A,
  mapping_table M
WHERE
  A.TYPE = M.TYPE

Так что мой вопрос в том, как я могу это сделать. Опять же, я не могу использовать динамический SQL, так как он должен отличаться для каждого типа записи, но если столбец может быть выбран на основе значения поля отображения, тогда будет работать sql obovemention.

Я понимаю, что это просто может быть невозможно (и может идти вразрез с философией разработки PL / SQL), и в этом случае я бы приветствовал любые ваши предложения о том, как решить эту проблему.

P.S .: Полагаю, можно было бы просто жестко закодировать функцию отображения, например ::

FUNCTION get_field(field_key IN VARCHAR(32), a NOCOPY IN table_a%rowtype) RETURN VARCHAR(2000) IS
  out VARCHAR2(2000)
BEGIN
  -- ...
  IF field_key = 'field_1' THEN
    RETURN a.field_1; END IF;
  -- ..
END;

Но это кажется действительно не элегантным.

1 Ответ

1 голос
/ 30 марта 2009

Вот некоторый код, который будет создавать динамический SQL из определений сопоставления. Для простоты я использовал таблицу EMP в качестве таблицы A, в качестве типа которой используется столбец DEPTNO.

declare
   q long;
   rc sys_refcursor;
   first boolean := true;
   l_field1 varchar2(100);
   l_field2 varchar2(100);

   function mapcol (p_field_mapping varchar2) return varchar2
   is
      l_retval varchar2(32);
   begin
      if p_field_mapping is not null then
         l_retval := 'to_char(a.' || p_field_mapping || ')';
      else
         l_retval := 'null';
      end if;
      return l_retval;
   end;
begin
   -- Construct dynamic SQL
   for r_map in (select * from mapping_table)
   loop
      if first then
         first := false;
      else
         q := q || ' union all ';
      end if;
      q := q || 'select ';
      q := q || mapcol(r_map.field_1_mapping) || ', ';
      q := q || mapcol(r_map.field_2_mapping);
      q := q || ' from emp a where a.deptno = ' || r_map.type;
   end loop;

   -- Run SQL and show results
   dbms_output.put_line('SQL = ' || q);
   dbms_output.put_line('');
   dbms_output.put_line('Results');
   dbms_output.put_line('-------');
   open rc for q;
   loop
      fetch rc into l_field1, l_field2;
      exit when rc%notfound;
      dbms_output.put_line(l_field1 || ', ' || l_field2);
   end loop;
end;

Затем я создал эту таблицу сопоставления:

SQL> create table mapping_table (type integer,
  2>   field_1_mapping varchar2(30), field_2_mapping varchar2(30));

Table created.

SQL> insert into mapping_table values (10, 'ENAME', 'SAL');

1 row created.

SQL> insert into mapping_table values (20, 'SAL', 'JOB');

1 row created.

SQL> insert into mapping_table values (30, 'JOB', 'HIREDATE');

1 row created.

SQL> commit;

Commit complete.

Когда я запускаю его (с включенным SERVEROUTPUT в SQL Plus), я получаю:

SQL = select to_char(a.ENAME), to_char(a.SAL) from emp a where a.deptno = 10
union all
select to_char(a.SAL), to_char(a.JOB) from emp a where a.deptno = 20
union all
select to_char(a.JOB), to_char(a.HIREDATE) from emp a where a.deptno = 30

Results
-------
CLARK, 7450
KING, 10000
TEST,
MILLER, 6500
BINNSY, 100
FARMER, 123
7975, MANAGER
4566, ANALYST
8000, ANALYST
5000, janitor
SALESMAN,
SALESMAN, 22-FEB-1981
SALESMAN, 28-SEP-1981
MANAGER, 01-MAY-1981
SALESMAN, 08-SEP-1981
MANAGER, 19-JUL-2008

PL/SQL procedure successfully completed.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...