zoukankan      html  css  js  c++  java
  • 一次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 link
      to_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 key
                    FROM user_constraints
                   WHERE constraint_type = 'R'
                     AND status = 'ENABLED') LOOP
          EXECUTE 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 constraints
                    FROM user_constraints
                   WHERE status = 'ENABLED') LOOP
          EXECUTE 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 as
        select * 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: 试图创建, 变更或删除正在使用的临时表中的索引

    declare
      v_table_name varchar2(32);
      v_sql        varchar2(2000);
      v_cnt number;
      
      cursor cur is
        select t.TABLE_NAME
          from user_tables t
         where t.TABLE_NAME
               in (select st.table_name
                     from user_tab_columns st
                    where st.DATA_TYPE in ('CLOB', 'BLOB'))
         order by t.TABLE_NAME;
    
    begin
    
      for i in cur loop
        v_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 then
           execute 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;
    
    exception
      when others then
        dbms_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?

    declare
      v_table_name varchar2(32);
      v_sql        varchar2(2000);
      v_cnt number;
      
      cursor cur is
        select t.TABLE_NAME
          from user_tables t
         where t.TABLE_NAME
               in (select st.table_name
                     from user_tab_columns st
                    where st.DATA_TYPE in ('CLOB', 'BLOB'))
         order by t.TABLE_NAME;
    
    begin
    
      for i in cur loop
        v_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 then
           execute 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 table1
        as' || '
        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;
    
    exception
      when others then
        dbms_output.put_line(v_table_name || ':' || sqlcode || ':' || sqlerrm);
      
    end get_data_from168;
    View Code

    后来想想,如果用Kettle的话会更方便,结果用Kettle测试了一下,Kettle对于lob字段处理的也非常好。

    之后Kettle会自动生成每个表对应的转换。

    测试运行也没什么问题,非常方便。

  • 相关阅读:
    Javascript的私有变量和方法、共有变量和方法以及特权方法、构造器、静态共有属性和静态共有方法
    Spring4整合Hibernate4出现的错误的解决
    Javascript类的创建
    Kettle学习总结(一)
    Kettle Excel导入数据到数据库
    Python 爬虫 2 (转)
    Js仿腾讯微博效果
    飘雪效果
    列表获取对应图片
    飞入购物车
  • 原文地址:https://www.cnblogs.com/Alex-Zeng/p/3988504.html
Copyright © 2011-2022 走看看