2010-04-13 109 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