2009-03-27 2 views
0

Есть ли способ получить доступ к динамически доступному элементу User- определенной записи, объекта или ссылочного курсора с использованием переменной? Например. Что-то вродеДинамически доступ к члену пользовательских объектов в PL/SQL

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-файл.

Я понимаю, что это может быть просто невозможно (и может противоречить философии проектирования 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

Вот какой код, который построит динамический 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 ON в 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. 
+0

Да, это так, как идти о Это. Он должен будет переструктурировать мою таблицу сопоставления, и она должна будет сделать некоторые уточнения, такие как порядок столбцов и проверка типа данных. Будет ли способ обанкротить это? – aggergren