动态访问PL / SQL中用户定义对象的成员

时间:2009-03-27 09:25:16

标签: dynamic plsql

有没有办法访问用户的动态访问成员 - 使用变量定义记录,对象或引用游标?例如。 像

这样的东西
  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,因为它对每种记录类型都有不同,但如果可以根据映射字段的值选择列,则obovemention 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 个答案:

答案 0 :(得分: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.

当我运行它时(在SQL Plus中使用SERVEROUTPUT ON),我得到:

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.