2010-04-13 68 views
4

我写加载从架构A一些数据架构B的PL/SQL程序,他们都非常不同的模式,我不能改变模式B的结构转换表列键值对

模式A中的各个表中的各列(在视图中连接在一起)需要作为表中的2列中的key =>值对插入到模式B中,每个列都在单独的行中。例如,一个员工的名字可能是存在于架构A employee.firstname,但需要在架构B被输入为:

id=>1, key=>'A123', value=>'Smith' 

有近100项,有更多的要添加的潜力在未来。这意味着我不想对这些键中的任何一个进行硬编码。

示例代码:

create table schema_a_employees (
    emp_id number(8,0), 
    firstname varchar2(50), 
    surname varchar2(50) 
); 
insert into schema_a_employees values (1, 'James', 'Smith'); 
insert into schema_a_employees values (2, 'Fred', 'Jones'); 

create table schema_b_values (
    emp_id number(8,0), 
    the_key varchar2(5), 
    the_value varchar2(200) 
); 

我想到了一个完美的解决方案将最有可能涉及查找表来确定插入什么样的价值为每个键,并没有涉及硬编码有效像数十个类似的语句.. ..

insert into schema_b_values (1, 'A123', v_firstname); 
insert into schema_b_values (1, 'B123', v_surname); 

我想什么,能够做的就是在架构A本地查找表,列出所有的键从架构B,与给出了的列名的列沿表格Schema A应该用来填充,例如模式A中的关键“A123”应填入模式A中的列“firstname”的值,例如,

create table schema_a_lookup (
    the_key varchar2(5), 
    the_local_field_name varchar2(50) 
); 
insert into schema_a_lookup values ('A123', 'firstname'); 
insert into schema_a_lookup values ('B123', 'surname'); 

但我不知道如何动态地使用查找表中的值告诉Oracle要使用哪些列。

所以我的问题是,是否有一个优雅的解决方案,用schema_a_employees中的数据填充schema_b_values表而不对每个可能的键(即A123,B123等)进行硬编码?

干杯。

+0

+!用于提供设置说明。这使测试解决方案变得更容易。 – APC 2010-04-13 15:27:26

回答

1

我真心希望你的Schema B不是dreadedkey-value pair设计。尽管在某些情况下某些动态属性值表可能很有用,但您会发现在EAV设计中几乎不可能写出几乎所有最基本的查询(即使是“找到所有名为John Smith的员工”很难写 - 也不可能调)。

不管怎样,在你的情况,你想写一个动态查询,将是这样的:

SQL> INSERT ALL 
    2  INTO schema_b_values VALUES (emp_id, 'A123', firstname) 
    3  INTO schema_b_values VALUES (emp_id, 'B123', surname) 
    4  SELECT emp_id, firstname, surname 
    5  FROM schema_a_employees; 

4 rows inserted 

您可以使用下面的查询生成语句:

SQL> SELECT 'INSERT ALL ' sql_lines FROM dual 
    2 UNION ALL 
    3 SELECT 'INTO schema_b_values VALUES (emp_id, ''' 
    4   || dbms_assert.simple_sql_name(the_key) 
    5   || ''', ' 
    6   || dbms_assert.simple_sql_name(the_local_field_name) 
    7   ||')' 
    8 FROM schema_a_lookup 
    9 UNION ALL 
10 SELECT 'SELECT * FROM schema_a_employees' FROM dual; 

SQL_LINES 
-------------------------------------------------------------------------------- 
INSERT ALL 
INTO schema_b_values VALUES (emp_id, 'A123', firstname) 
INTO schema_b_values VALUES (emp_id, 'B123', surname) 
SELECT * FROM schema_a_employees 

然后,您可以使用EXECUTE IMMEDIATE或DBMS_SQL来执行该语句。

+0

完美,这正是我所寻找的,谢谢。不幸的是,模式B确实是令人恐惧的键值设计,但它是遗留的,并且在我的控制之外。很好的解决方案,谢谢。 – 2010-04-14 11:24:16

1

我喜欢INSERT ALL作为一种方法,因为它提供了一个封装事务:要么插入所有行,要么没有。我对数据迁移的经验是它往往是一个高度迭代的过程,所以任何有助于清理和回归的东西都是一个明显的好处。

SQL> declare 
    2  l_src_name varchar2(30) := 'SCHEMA_A_EMPLOYEES'; 
    3  l_tgt_name varchar2(30) := 'SCHEMA_B_VALUES'; 
    4  stmt varchar2(32767); 
    5 begin 
    6  for pk_rec in (select cc.table_name, cc.column_name 
    7      from user_cons_columns cc 
    8        , user_constraints c 
    9      where c.table_name = l_src_name 
10      and c.constraint_type = 'P' 
11      and cc.table_name = l_src_name) 
12  loop 
13   stmt := 'insert all'; 
14   for col_rec in (select * from schema_a_lookup) 
15   loop 
16    stmt := stmt||' into '||l_tgt_name||' values (' 
17     ||pk_rec.column_name 
18     ||', '''||col_rec.the_key||''',' 
19     ||col_rec.the_local_field_name 
20     ||')'; 
21   end loop; 
22   stmt := stmt||' select * from '||l_src_name; 
23  end loop; 
24  execute immediate stmt; 
25 end; 
26/

PL/SQL procedure successfully completed. 

SQL> 

有多少行?

SQL> select * from schema_b_values; 

    EMP_ID THE_K THE_VALUE 
---------- ----- --------------- 
     1 A123 James 
     2 A123 Fred 
     1 B123 Smith 
     2 B123 Jones 

SQL> 

我已经将查询包装在PL/SQL中,因为它指向了进一步自动化的方式。您可以添加一个表来保存SOURCE和TARGET表名。显然,如果源表有一个复合主键,那么有一定的乐趣。

+0

不错,我没有想过在这里使用数据字典。 – 2010-04-14 11:27:16