最近做的一個oracle數據遷移功能,如有更好的方案,請各位大蝦也能告訴小弟。

需求場景:

業務系統環境升級,數據庫表結構有變動,需要將原數據庫中的所有數據導入到新的數據表結構中。

說到這裏,大家腦海中可能一下會冒出很多方案,如:

1、使用exp和imp

2、使用dblink

 

針對第一種方案是行不通的,因爲imp導入,必須保證用戶下面是乾淨的,沒有任何與dmp中重複的對象,不然就會導致數據無法正確導入。

針對第二種方案,dblink一般使用場景是在兩臺及以上服務器之間進行數據遷移,dblink它只爲在兩個服務器之間建立一個可互相訪問的橋樑,最終還是需要進行insert into table select * from table。

 

以下是我自己實現的方案

思路:創建一個臨時用戶,刷入最新表結構,此時表中無任何數據,通過查詢all_tables視圖,查詢出老用戶的所有表對象,並通過查詢dba_tab_columns視圖,查詢出每一個表的數據列,因爲新表相對舊錶有新增字段(注:這些新增字段是允許爲null的,不然這種方案不一定好例),再通過insert into table(columns) select columns from table語句將數據批量插入到新表中;同時爲防止後續數據插入引起主鍵衝突,還需修改每個表對應序列的開始值,通過查詢dba_sequences視圖,將老用戶中的所有序列對象名和last_number查詢出來,再在新用戶中通過刪除老序列,創建新序列改變它的start with值即可。

 

步驟如下:

創建一個臨時用戶,刷入最新的表結構,並通過超管賦予如下權限,因爲這些權限在做數據遷移時會用到

 

grant select on all_tables to TEMP_SDU;
grant select on dba_tab_columns to TEMP_SDU;
grant select on dba_sequences to TEMP_SDU;
grant connect,dba,resource to TEMP_SDU;
grant alter any sequence to TEMP_SDU;
grant create any sequence to TEMP_SDU;
grant execute any procedure to TEMP_SDU;
grant select any table to TEMP_SDU;

 

創建如下三個存儲過程:

--獲取表中的數據列,並進行批量插入

--table_name 表名
--temp_user 臨時用戶名
create or replace procedure p_getcolumns(table_name varchar2,temp_user varchar2)
as
  type ref_table_cursor is ref cursor;
  table_cursor ref_table_cursor;
  column_name varchar2(200);
  str_table_name varchar2(200);
  print_column varchar2(10000);
  str_sql varchar2(10000);
begin
    str_table_name := table_name;
 --Check out all the temporary user table column
    open table_cursor for select t.COLUMN_NAME from dba_tab_columns t where t.TABLE_NAME=str_table_name and t.OWNER=temp_user;
    loop
         fetch table_cursor into column_name;
         exit when table_cursor%notfound;
              --dbms_output.put_line(str_table_name||'--'||column_name);
              print_column := print_column||column_name||',';
    end loop;
    close table_cursor;
    print_column := substr(print_column,1,length(print_column)-1);
    str_sql := 'insert into '||table_name||'('||print_column||') select '||print_column||' from '||temp_user||'.'||table_name;
    --dbms_output.put_line(str_table_name||'--'||str_sql);
    execute immediate str_sql;
    commit;

    print_column := '';
    str_sql := '';
end p_getcolumns;
/

--修改序列開始值

--temp_user 臨時用戶名

create or replace procedure p_modify_sequences(temp_user varchar2)
as
    cursor cur_sequence is select sequence_name from dba_sequences where sequence_owner=temp_user and sequence_name not like '%S_BME%';
    seq_name varchar2(50);
    sequence_num number;
    num_count number;
begin
    open cur_sequence;
    loop
         fetch cur_sequence into seq_name;
         exit when cur_sequence%notfound;
              
              select count(*) into num_count from dba_sequences s where s.sequence_owner=temp_user and s.sequence_name=seq_name;
              
              if num_count>0 then
                 select s.last_number into sequence_num from dba_sequences s where s.sequence_owner=temp_user and s.sequence_name=seq_name;
                 select count(*) into num_count from dba_sequences s where s.sequence_owner='TEMP_SDU' and s.sequence_name=seq_name;
                 if num_count>0 then
                    execute immediate 'drop sequence '||seq_name;
                 end if;
                 execute immediate 'create sequence '||seq_name||' minvalue 1 maxvalue 999999999999 start with '||sequence_num||' increment by 1 nocache cycle';
                 
               end if;
              
    end loop;
    close cur_sequence;
    exception
    when no_data_found then
         sequence_num:=1;
         dbms_output.put_line(sqlerrm);
    when others then
         sequence_num:=1;
         dbms_output.put_line(sqlerrm);

end p_modify_sequences;
/

--數據遷移調用的入口存儲過程
create or replace procedure p_datamove(temp_user varchar2)
as

  type ref_table_cursor is ref cursor;
  table_cursor ref_table_cursor;
  column_name varchar2(200);
  --All the tables in the query in temporary user
  cursor cur is select t.table_name from all_tables t where t.owner=temp_user and t.table_name not in('ECONF_ADMIN_INFO','ECONF_OPERATOR_PSWD_INFO','ECONF_EMAILSERVER','ECONF_HIREPORTS_INFO','ECONF_CONFIG','ECONF_EMAIL_FORMAT','ECONF_MS_FILE','ECONF_SVC_FEATURE_DATA','ECONF_IVR_VOICE_FILE','ECONF_IVR_VOICE_FILE_MCU','ECONF_SVC_DATA');
  str_sql varchar2(200);
  table_name varchar2(200);
  isexist number;

begin

  --savepoint p1;
  --Traverse each table name in the cursor
  open cur;
  loop
      fetch cur into table_name;
      exit when cur%NOTFOUND;
          select instr(table_name,'ECONF_') into isexist from dual;
          if isexist>0  then
                 --Get all the columns in the table, and the migration of data in each table
                 p_getcolumns(table_name,temp_user);
          end if;

  end loop;
  close cur;

  --modify sequences value
  p_modify_sequences(temp_user);

  exception
    when others then
         dbms_output.put_line(sqlerrm);
         --rollback to savepoint p1;

end p_datamove;
/

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章