一次Oracle数据迁移
目標數據庫:Oracle?Database?10g Enterprise Edition Release 10.2.0.3.0?
源數據庫 ?:?Oracle Database 11g Enterprise Edition Release 11.2.0.1.0
?
1.首先想到的是用expdp,impdp。
?通過交流發現無法得到源數據庫的操作系統密碼,這樣一來expdp,impdp就不好使了。
?
2.其次想到的是用plsql developer 來導出數據,但是導出的時候報錯了。
放棄此種方法。
3.由于數據量不是很大,考慮使用數據庫鏈的方式來完成。
?a.在目標數據庫上創建數據庫鏈,鏈接到目標數據庫。
create public database linkto_168_bi22 connect to "bi41" identified by "bi41" using '(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST =172.21.1.68)(PORT = 1521)))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = orcl)))';?b.得到用戶對象的定義語句?dbms_metadata.get_ddl('TABLE','ACT_GE_BYTEARRAY')
?在此糾結了一下,是直接用過程腳本來創建表,還是先生成建表語句,之后再循環灌數據。
c.選擇先創建用戶對象,之后再插入數據。
?這個選擇給后續的數據插入帶來了一些麻煩,就是索引和約束,特別是外鍵約束。
在腳本中加入了禁用約束的語句
FOR i IN (SELECT table_name, constraint_name --disable first the foreign keyFROM user_constraintsWHERE constraint_type = 'R'AND status = 'ENABLED') LOOPEXECUTE IMMEDIATE 'alter table "' || i.table_name || '" disable constraint ' ||i.constraint_name;END LOOP i;FOR i IN (SELECT table_name, constraint_name -- then disable all constraintsFROM user_constraintsWHERE status = 'ENABLED') LOOPEXECUTE IMMEDIATE 'alter table "' || i.table_name || '" disable constraint ' ||i.constraint_name;END LOOP i;感覺OK的時候,又報錯了。
?ERROR: ?ORA-22992:?cannot?use?LOB?locators?selected?from?remote?tables?
原來表中有些是LOB字段,無法通過數據鏈訪問直接訪問。
最后想到用Oracle的全局臨時表的方式將數據抽取過來。
這里也有一個小插曲,就是有50多個表都是有lob字段的。
想寫一個循環利用動態SQL來創建global temporary table,并且每次創建之前刪除掉改全局臨時表。
v_sql := 'create global temporary table table1 ON COMMIT PRESERVE ROWS asselect * from ' || v_table_name;execute immediate v_sql;v_sql := 'insert into table1 ' || 'select * from ' || v_table_name || '@to_168_bi';execute immediate v_sql;v_sql := 'insert into ' || v_table_name || 'select * from table1';execute immediate v_sql;
commit;
?
這樣創建的臨時表默認是?COMMIT delete ROWS 的。
發現數據沒有抽取過來,初步懷疑是動態執行SQL的時候自動提交了,這里有些沒有想清楚。
之后創建全局臨時表的時候加上了ON COMMIT PRESERVE ROWS。
數據是抽過來了,但是drop的時候會報錯:ORA-14452: 試圖創建, 變更或刪除正在使用的臨時表中的索引
declarev_table_name varchar2(32);v_sql varchar2(2000);v_cnt number;cursor cur isselect t.TABLE_NAMEfrom user_tables twhere t.TABLE_NAMEin (select st.table_namefrom user_tab_columns stwhere st.DATA_TYPE in ('CLOB', 'BLOB'))order by t.TABLE_NAME;beginfor i in cur loopv_table_name := i.table_name;v_sql := 'truncate table ' || v_table_name;execute immediate v_sql;select count(1) into v_cnt from user_tables t where t.TABLE_NAME=upper('table1');if v_cnt >0 thenexecute immediate 'drop table table1';end if; v_sql := 'create global temporary table table1 ON COMMIT PRESERVE ROWS as' || 'select * from ' || v_table_name ||'@to_168_bi';execute immediate v_sql;v_sql := 'insert into ' || v_table_name || 'select * from table1';execute immediate v_sql;commit;end loop;exceptionwhen others thendbms_output.put_line(v_table_name || ':' || sqlcode || ':' || sqlerrm);end get_data_from168; View Code之后測試了一下,
SQL> create global temporary table table1 as select * from employees;Table created.SQL> drop table table1;Table dropped.SQL> create global temporary table table1 on commit preserve rows as select * from employees;Table created.SQL> drop table table1; drop table table1* ERROR at line 1: ORA-14452: attempt to create, alter or drop an index on temporary table already in use實驗證明創建glob temporary table 的時候如果添加了on commit preserve rows在session沒有退出的情況下是沒發drop的。
之后這樣寫在SQLplus 中執行卻沒什么問題,plsql developer 的test procedure的方式是多session?
declarev_table_name varchar2(32);v_sql varchar2(2000);v_cnt number;cursor cur isselect t.TABLE_NAMEfrom user_tables twhere t.TABLE_NAMEin (select st.table_namefrom user_tab_columns stwhere st.DATA_TYPE in ('CLOB', 'BLOB'))order by t.TABLE_NAME;beginfor i in cur loopv_table_name := i.table_name;v_sql := 'truncate table ' || v_table_name;execute immediate v_sql;select count(1) into v_cnt from user_tables t where t.TABLE_NAME=upper('table1');if v_cnt >0 thenexecute immediate 'drop table table1';end if; /* v_sql := 'create global temporary table table1 ON COMMIT PRESERVE ROWS as' || 'select * from ' || v_table_name ||'@to_168_bi';execute immediate v_sql;*/v_sql := 'create global temporary table table1as' || 'select * from ' || v_table_name;execute immediate v_sql;execute immediate ('insert into table1 select * from '||v_table_name||'@to_168_bi');v_sql := 'insert into ' || v_table_name || 'select * from table1';execute immediate v_sql;commit;end loop;exceptionwhen others thendbms_output.put_line(v_table_name || ':' || sqlcode || ':' || sqlerrm);end get_data_from168; View Code后來想想,如果用Kettle的話會更方便,結果用Kettle測試了一下,Kettle對于lob字段處理的也非常好。
之后Kettle會自動生成每個表對應的轉換。
測試運行也沒什么問題,非常方便。
?
轉載于:https://www.cnblogs.com/Alex-Zeng/p/3988504.html
總結
以上是生活随笔為你收集整理的一次Oracle数据迁移的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分治法 Strassen算法计算方阵相乘
- 下一篇: 编译安装Apache2.4.10