导出数据、生成SQL INSERT的方法。

在工作中常常碰到这种情况:我们需要将一个应用系统的基础数据导出来,以便基础数据下次导入到另外一个场景。

事实上,这种情况我们可以用pl/sql的功能Export Tables来实现。Export Table有三种导出方式:Oracle Export,SQL Insert,PL/SQL Developer。通常我们会使用Oracle Export,SQL Insert的功能。(第三种俺没用过,呵呵,所以这么说。)

Oracle Export是将数据导出成dmp格式的文件,这样有个麻烦,不能看到里面的内容。虽然它的速度很快,但是缺点太明显,所以至少我一般不用它。除非是导出含有clob,blob的表,才会用到这个功能。

SQL Insert是最实用的功能。当然它也有缺点,比如不能使用clob,blob。但是优点明显,就是能看到sql语句的详细内容。所以一般我用它,除非clob,blob才用export tables的功能。

实际中,一个系统可能有几百个表,但是基础数据表可能才100多个,这样使用PL/SQL的SQL Insert功能就会出现一种情况:每次我导出基础数据的时候,就要从用户的几百个表中选择那100多个表。这样很考验人的耐心的,反正我是被这个搞得头晕眼花。

正是因为我没耐心,所以就写了这片短文,希望在今后的工作中,能用更快的速度来完成导出导入功能,所以就自己做了一个方法,来完成导入导出功能,最终的效果应该是和PL/SQL里面的SQL Insert功能一样的,且个人觉得更适合本人使用(不知道适合不适合别人使用,呵呵)。

************************************************************************************************************

闲话少说,开始正题吧。

主要思路是这样的:

1,将基础数据的表名插入到临时表t_proc_init_tab中,不论顺序,表结构如下:

create table T_PROC_INIT_TAB
(
  TABLE_NAME VARCHAR2(100)
)

2,分析临时表t_proc_init_tab中所有表的依赖关系,最后算出所有表的依赖等级,插入到临时表T_PROC_CONSTRAINT_GRADE中。等级越高,标识该表依赖程度越高。后面插入数据的时候就会在后面执行。T_PROC_CONSTRAINT_GRADE的表结构如下:

create table T_PROC_CONSTRAINT_GRADE
(
  SRC_TABLE       VARCHAR2(100) not null,
  GRADE           NUMBER not null
)

算出表依赖等级,使用后面存储过程PKG_CREATE_INS_SQL.SP_DoConstraint。

3,依据依赖等级高低,从低到高,一个一个的导出表的数据,生成SQL Insert到临时表t_proc_exp_sqlinsert中,t_proc_exp_sqlinsert的表结构如下:

create table T_PROC_EXP_SQLINSERT
(
  ID         NUMBER not null,
  SQLINFO    VARCHAR2(2000),
  TABNAME    VARCHAR2(100),
  CREATEDATE DATE
)

执行这个步骤,使用后面存储过程PKG_CREATE_INS_SQL.SP_MAIN。

4,使用spool,生成基础数据的txt文件。

set trimspool on
set linesize 120
set pagesize 2000
set newpage 1
set heading off
set term off
spool d:/boss_init_data.sql
select pes.sqlinfo||';' from t_proc_exp_sqlinsert pes order by id;
spool off

 

5,最后在d:盘下,找到boss_init_data.sql文件,这个就是基础数据的导入文件,下次用的使用在PL/SQL的COMMAND WINDOW下直接使用@@d:/boss_init_data.sql; 这个命令,就可以将数据导入到表中去了。

 

这样,以后不用每次都去从几百个表中查找那100多个表了,直接执行存储过程就行了。利索多了,呵呵。

 

************************************************************************************************************

附录存储过程包:

create or replace package PKG_CREATE_INS_SQL is
  /***************************************************************
  *函 数 名:  生成sql insert语句
  *函数功能:
  *作者:      ham
  *编写日期:  2010-04-28
  *输入:
  *输出:
  *返 回 值:
  ***************************************************************/
  -- 单表生成sql insert语句
  Procedure SP_CREATE(i_tablename in varchar2);

  --分析所有表的依赖关系。以等级排列。
  procedure SP_DoConstraint(o_returncode out varchar2, --
                            o_returnmsg  out varchar2);

  --查询单表的依赖等级。
  function GETTABLEGRADE(i_table in varchar2 --表名
                         ) return number;
  --主程序
  procedure SP_MAIN(o_returncode out varchar2, --
                    o_returnmsg  out varchar2);

end PKG_CREATE_INS_SQL;
/
create or replace package body PKG_CREATE_INS_SQL is
  /***************************************************************
  *函 数 名:  生成sql insert语句
  *函数功能:
  *作者:      ham
  *编写日期:  2010-04-28
  *输入:
  *输出:
  *返 回 值:
  ***************************************************************/
  --
  Procedure SP_CREATE(i_tablename in varchar2) is
    l_head    varchar2(2000);
    l_tabhead varchar2(2000);
    l_tabval  varchar2(2000);
    l_idx     number;
    --可变数组
    type type_array is table of varchar2(20) index by binary_integer;
    coltype_array type_array;
    colname_array type_array;
 
    --字段类型
    cursor c_col is
      select utc.COLUMN_NAME, utc.DATA_TYPE
        from user_tab_columns utc
       where utc.TABLE_NAME = i_tablename;
 
    type t_cur is ref cursor;
    c_cur_tab  t_cur;
    strSQL     VARCHAR2(2000);
    l_tabvalue VARCHAR2(2000);
 
    TYPE table_forall IS TABLE OF T_PROC_TMP_COLVAL%ROWTYPE;
    v_table table_forall;
 
    l_num    number;
    l_tmpidx number;
  begin
    l_idx    := 0;
    l_head   := '';
    l_tabval := '';
 
    select wm_concat(utc.COLUMN_NAME)
      into l_tabhead
      from user_tab_columns utc
     where utc.TABLE_NAME = i_tablename;
 
    l_tabhead := 'insert into ' || i_tablename || '(' || l_tabhead || ') ';
 
    for c_cl in c_col loop
      l_idx := l_idx + 1;
      coltype_array(l_idx) := c_cl.data_type;
      colname_array(l_idx) := c_cl.column_name;
   
      if coltype_array(l_idx) = 'DATE' then
        l_head := l_head || 'to_char(' || colname_array(l_idx) || ',' || '''' ||
                  'yyyy-mm-dd hh24:mi:ss' || '''' || ')||' || '''' || '@@' || '''' || '||';
      else
        l_head := l_head || colname_array(l_idx) || '||' || '''' || '@@' || '''' || '||';
      end if;
    end loop;
 
    insert /*+ append */
    into t_proc_exp_sqlinsert nologging
      (id, sqlinfo, tabname, createdate)
    values
      (seq_inssqlid.nextval,
       'delete from ' || i_tablename,
       i_tablename,
       sysdate);
 
    insert /*+ append */
    into t_proc_exp_sqlinsert nologging
      (id, sqlinfo, tabname, createdate)
    values
      (seq_inssqlid.nextval, 'commit', i_tablename, sysdate);
 
    l_head := substr(l_head, 0, length(l_head) - 8);
    strSQL := 'select ' || l_head || ' from ' || i_tablename;
    open c_cur_tab for strSQL;
    loop
      fetch c_cur_tab
        into l_tabvalue;
      exit when c_cur_tab %notfound;
   
      select column_value BULK COLLECT
        into v_table
        from table(fn_split(l_tabvalue, '@@'));
   
      l_tabval := '';
      l_num    := 0;
      FOR i IN 1 .. v_table.count LOOP
        l_num := l_num + 1;
     
        if coltype_array(l_num) = 'CHAR' or
           coltype_array(l_num) = 'VARCHAR2' or
           coltype_array(l_num) = 'NVARCHAR2' then
          l_tabval := l_tabval || ',' || '''' || v_table(i).colval || '''';
        elsif coltype_array(l_num) = 'NUMBER' or
              coltype_array(l_num) = 'LONG' then
          l_tabval := l_tabval || ',' || v_table(i).colval;
        elsif coltype_array(l_num) = 'DATE' then
          l_tmpidx := instr(v_table(i).colval, '00:00:00');
       
          if l_tmpidx = 12 then
            l_tabval := l_tabval || ',' || 'to_date(' || '''' ||
                        substr(v_table(i).colval, 1, 10) || '''' || ',' || '''' ||
                        'yyyy-mm-dd' || '''' || ')';
          else
            l_tabval := l_tabval || ',' || 'to_date(' || '''' || v_table(i)
                       .colval || '''' || ',' || '''' ||
                        'yyyy-mm-dd hh24:mi:ss' || '''' || ')';
          end if;
        else
          l_tabval := l_tabval || ',' || '''' || '''';
        end if;
      END LOOP;
   
      l_tabval := substr(l_tabval, 2);
      l_tabval := 'values(' || l_tabval || ')';
      l_tabval := l_tabhead || l_tabval;
   
      insert /*+ append */
      into t_proc_exp_sqlinsert nologging
        (id, sqlinfo, tabname, createdate)
      values
        (seq_inssqlid.nextval, l_tabval, i_tablename, sysdate);
   
    end loop;
    close c_cur_tab;
 
    insert /*+ append */
    into t_proc_exp_sqlinsert nologging
      (id, sqlinfo, tabname, createdate)
    values
      (seq_inssqlid.nextval, 'commit', i_tablename, sysdate);
 
    commit;
  exception
    when others then
      rollback;
  end;

  --分析所有表的依赖关系。以等级排列。
  procedure SP_DoConstraint(o_returncode out varchar2, --
                            o_returnmsg  out varchar2) is
    cursor c_tab is
      select distinct ut.table_name from user_tables ut;
    l_grade number;
  begin
    delete from t_proc_constraint_grade;
 
    for c_ta in c_tab loop
      l_grade := gettablegrade(c_ta.table_name);
    end loop;
    commit;
    o_returncode := '1';
    o_returnmsg  := 'good';
  exception
    when others then
      o_returncode := '0';
      o_returnmsg  := 'bad' || SQLERRM;
  end;

  --查询单表的依赖等级。
  function GETTABLEGRADE(i_table in varchar2 --表名
                         ) return number is
    l_grade    number;
    l_num      number;
    l_pretable varchar2(100);
    l_pregrade number;
 
    --根据表名查外键
    cursor c_constraint is
      select a.constraint_name constraint_name,
             a.table_name      origial_table,
             b.table_name      refer_table
        from user_constraints a, user_constraints b
       where a.constraint_type = 'R'
         and a.r_constraint_name = b.constraint_name
         and a.table_name = upper(i_table);
  begin
    l_grade := 1;
 
    --查询临时表中的表的等级
    select count(1)
      into l_num
      from t_proc_constraint_grade pcg
     where pcg.src_table = i_table;
 
    --存在表的等级,则取出等级
    if l_num > 0 then
      select pcg.grade
        into l_grade
        from t_proc_constraint_grade pcg
       where pcg.src_table = i_table;
   
      return l_grade;
    end if;
 
    --查询表上的外键数量
    select count(1)
      into l_num
      from user_constraints a, user_constraints b
     where a.constraint_type = 'R'
       and a.r_constraint_name = b.constraint_name
       and a.table_name = upper(i_table);
 
    if l_num = 0 then
      --该表无外键,插入临时表,等级为1。     
      insert into t_proc_constraint_grade
        (src_table, grade)
      values
        (i_table, 1);
   
      l_grade := 1;
    else
      --该表有多个外键。比较涉及表的等级,取最大的等级。
      for c_ct in c_constraint loop
        l_pretable := c_ct.refer_table;
        l_pregrade := gettablegrade(l_pretable);
     
        if l_pregrade + 1 >= l_grade then
          l_grade := l_pregrade + 1;
        end if;
      end loop;
      --插入等级表   
      insert into t_proc_constraint_grade
        (src_table, grade)
      values
        (i_table, l_grade);
    end if;
 
    return l_grade;
  end;

  procedure SP_MAIN(o_returncode out varchar2, --
                    o_returnmsg  out varchar2) is
    cursor c_initab is
      select pcg.src_table
        from t_proc_init_tab pit, t_proc_constraint_grade pcg
       where pit.table_name = pcg.src_table
       order by pcg.grade;
  begin
 
    for c_it in c_initab loop
      sp_create(c_it.src_table);
    end loop;
 
    o_returncode := '1';
    o_returnmsg  := 'good';
  exception
    when others then
      o_returncode := '0';
      o_returnmsg  := 'bad' || SQLERRM;
  end;

end PKG_CREATE_INS_SQL;
/

 

************************************************************************************************************

后序

这个存储过程其实写的还是有些问题的,但基本能用。以后如果有时间再看看能不能升级下。如果哪位看官有好的建议,俺也可以试试你的建议。呵呵。

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值