设为首页 收藏本站
查看: 1359|回复: 0

[经验分享] oracle转greenplum功能实现

[复制链接]
累计签到:77 天
连续签到:1 天
发表于 2014-5-27 10:09:25 | 显示全部楼层 |阅读模式
项目中遇到的,对greenplum不是很熟悉,所以花了一天完成的东西,主要用来将
oracle的表定义信息转换成greenplum形式,可以实现批量化,不用powerdisger一
个个点了。

功能说明:

  将oracle的表(表结构定义、约束、默认值及分区信息)定义信息转换成greenplum
格式。

包说明:



    create or replace package metadata_ora2gp as
      function split(in_tablist in varchar2) return dbms_sql.varchar2a;
      procedure convert_tab_create_ddl(in_tablist varchar2);
      procedure convert_index_create_ddl(in_tablist varchar2);
      procedure convert_constraint_ddl(in_tablist varchar2);
    end;
    /


包体:



    create or replace package body metadata_ora2gp as

      function split(in_tablist in varchar2) return dbms_sql.varchar2a as
        v_tablist dbms_sql.varchar2a;
      begin
      
        select distinct trim(regexp_substr(regexp_replace(in_tablist,
                                                           '([^ .
    ]+) +|[.]([^ .
    ]+)',
                                                           '\1.\2'),
                                            '[^
    ]+',
                                            1,
                                            level)) bulk collect
          into v_tablist
          from dual
        connect by level <= regexp_count(in_tablist, chr(10)) - 1;
      
        return v_tablist;
      end split;

      procedure convert_tab_create_ddl(in_tablist varchar2) as
        /*
          Author: Zhangyu@BI
          CreateDate: 2014/05/14
          Version: 1.0Beta
          Function: convert oracle table create ddl to greenplum table create ddl.
         
          11g支持分区模式:RANGE-RANGE、LIST-RANGE、LIST-HASH和LIST-LIST。
        */
        v_dk varchar2(4000); --greenplum dk键
        v_ddl_stmt clob; --ddl语句变量
        v_tablist dbms_sql.varchar2a; --表名数组,格式为owner.table_name
      
        --列信息游标,包括字段类型、默认值及非空值等
        cursor cur_collist(in_tab varchar2) is
          select mtc.OWNER,
                 mtc.TABLE_NAME,
                 mtc.COLUMN_NAME,
                 mtc.DATA_TYPE,
                 mtc.DATA_LENGTH,
                 mtc.DATA_PRECISION,
                 mtc.DATA_SCALE,
                 mtc.NULLABLE,
                 mtc.COLUMN_ID,
                 replace(lower(mtc.DATA_DEFAULT), 'sysdate', 'current_date') as DATA_DEFAULT, --greenplum中没有sysdate函数
                 t.gp_type_name
            from sys.my_tab_columns mtc, ORA2GP_TYPE_MAPPING t
           where mtc.OWNER || '.' || mtc.TABLE_NAME in (upper(in_tab))
             and mtc.DATA_TYPE = t.ora_type_name(+)
           order by mtc.COLUMN_ID;
      
        type collist_tab is table of cur_collist%rowtype;
        v_collist collist_tab;
      
        v_finalcol varchar2(32767); --存放单列信息的变量
      
        type part_rec is record(
          col1 varchar2(4000),
          col2 varchar2(4000));
        type part_tab is table of part_rec;
        v_part part_tab; --存放单个分区信息的数组
      
        v_partsql clob; --存放最终分区语句的变量
      
      begin
        /************************************************************************************/
        --拆分参数存放入表清单数组
        /*
          格式必须为:
          owner.table_name
          或者
          owner table_name
        */
        v_tablist := metadata_ora2gp.split(in_tablist);
      
        /************************************************************************************/
        --生成表定义语句
      
        for loop_idx in 1 .. v_tablist.count loop
        
          open cur_collist(v_tablist(loop_idx));
        
          if cur_collist%notfound then
            v_collist := null;
            dbms_output.put_line('Error: no ' || v_tablist(loop_idx) ||
                                 ' table.');
         
          else
         
            fetch cur_collist bulk collect
              into v_collist;
            close cur_collist;
         
          end if;
        
          for inner_idx in 1 .. v_collist.count loop
         
            --列映射转换
            select v_collist(inner_idx).column_name || ' ' || case
                      when v_collist(inner_idx)
                       .data_type in ('VARCHAR2', 'NVARCHAR2', 'CHAR', 'NCHAR') then
                       v_collist(inner_idx)
                       .gp_type_name || '(' || v_collist(inner_idx).data_length || ')'
                      when v_collist(inner_idx).data_type like 'TIMESTAMP%' then
                       v_collist(inner_idx).data_type
                      else
                       v_collist(inner_idx).gp_type_name
                    end || case
                      when v_collist(inner_idx).nullable = 'N' then
                       ' NOT NULL '
                      else
                       ' '
                    end || case
                      when v_collist(inner_idx).data_default is not null then
                       ' DEFAULT ' || v_collist(inner_idx).data_default
                      else
                       ' '
                    end
              into v_finalcol
              from dual;
         
            --拼接create table sql
            if inner_idx = 1 then
              if v_collist.count = 1 then
                v_ddl_stmt := 'create table ' || v_collist(inner_idx).owner || '.' || v_collist(inner_idx)
                             .table_name || '(' || v_finalcol || ')' || chr(10);
              else
                v_ddl_stmt := 'create table ' || v_collist(inner_idx).owner || '.' || v_collist(inner_idx)
                             .table_name || '(' || v_finalcol || ',' || chr(10);
              end if;
            elsif inner_idx = v_collist.last then
            
              /************************************************************************************/
              --生成distrubited key
              <<DKGeneratedBlock>>
              begin
                with t as
                 (select listagg(dic.COLUMN_NAME, ',') within group(order by dic.COLUMN_POSITION) as collist,
                         count(*) as col_cnt,
                         min(count(*)) over() min_col_cnt
                    from dba_indexes dc, dba_ind_columns dic
                   where dc.table_owner || '.' || dc.table_name in
                         (upper(v_collist(inner_idx)
                                .owner || '.' || v_collist(inner_idx).table_name))
                     and dc.uniqueness = 'UNIQUE'
                     and dc.owner = dic.INDEX_OWNER
                     and dc.index_name = dic.INDEX_NAME
                   group by dic.INDEX_OWNER, dic.INDEX_NAME)
                select ' DISTRIBUTED BY(' || collist || ') '
                  into v_dk
                  from t
                 where col_cnt = min_col_cnt;
              
              exception
                when others then
                  v_dk := '';
              end;
              <<DKGeneratedBlock>>
            
              v_ddl_stmt := v_ddl_stmt || v_finalcol || ')' || chr(10) || v_dk;
            else
              v_ddl_stmt := v_ddl_stmt || v_finalcol || ',' || chr(10);
            end if;
         
          end loop;
          /************************************************************************************/
          --生成分区语句
          <<PartitionGeneratedBlock>>
          begin
         
            with t1 as
             (select dpt.partitioning_type, dpt.subpartitioning_type
                from dba_part_tables dpt
               where dpt.partitioning_type not in ('HASH')
                 and dpt.subpartitioning_type not in ('HASH')
                    --gp默认是hash分区
                    --缺陷:list-hash分区也被排除
                 and dpt.owner || '.' || dpt.table_name in
                     (upper(v_tablist(loop_idx)))),
            t2 as
             (select listagg(dpkc.column_name, ',') within group(order by dpkc.column_position) pkcol
                from dba_part_key_columns dpkc
               where dpkc.owner || '.' || dpkc.name = upper(v_tablist(loop_idx))),
            t3 as
             (select listagg(dskc.column_name, ',') within group(order by dskc.column_position) spkcol
                from dba_subpart_key_columns dskc
               where dskc.owner || '.' || dskc.name = upper(v_tablist(loop_idx))),
            t4 as
             (select ' partition by ' || partitioning_type || '(' || pkcol || ')' ||
                     chr(10) || ' subpartition by ' || subpartitioning_type || '(' ||
                     spkcol || ')' part_col,
                     t1.*,
                     t2.*,
                     t3.*
                from t1
                left outer join t2
                  on 1 = 1
                left outer join t3
                  on 1 = 1),
            t5 as
             (select dtp.partition_name,
                     dtp.partition_position,
                     case
                       when regexp_like(dtp.high_value, '^TO_DATE *[(]') then
                        'timestamp ''' ||
                        trim(regexp_substr(dtp.high_value, '[^'']+', 1, 2)) || ''''
                       else
                        dtp.high_value
                     end as high_value, --修
                     dtsp.partition_name as ppname,
                     dtsp.subpartition_name,
                     dtsp.subpartition_position,
                     case
                       when regexp_like(dtsp.high_value, '^TO_DATE *[(]') then
                        'timestamp ''' ||
                        trim(regexp_substr(dtsp.high_value, '[^'']+', 1, 2)) || ''''
                       else
                        dtsp.high_value
                     end as sphval --修
                from sys.my_tab_partitions dtp, sys.my_tab_subpartitions dtsp
               where dtp.table_owner || '.' || dtp.table_name =
                     upper(v_tablist(loop_idx))
                 and dtp.table_name = dtsp.table_name(+)
                 and dtp.table_owner = dtsp.table_owner(+)
                 and dtp.partition_name = dtsp.partition_name(+)),
            t6 as
             (select case
                       when upper(high_value) in ('DEFAULT', 'MAXVALUE') then
                        ' DEFAULT PARTITION other '
                       else
                        ' partition ' || partition_name || case
                          when partitioning_type = 'RANGE' then
                           ' start (' || high_value || ') INCLUSIVE '
                          when partitioning_type = 'LIST' then
                           ' values(' || high_value || ')'
                          else
                           null
                        end
                     end as p_key,
                     case
                       when upper(sphval) in ('DEFAULT', 'MAXVALUE') then
                        ' DEFAULT SUBPARTITION other '
                       else
                        ' subpartition ' || subpartition_name || case
                          when subpartitioning_type = 'RANGE' then
                           ' start(' || sphval || ') INCLUSIVE'
                          when subpartitioning_type = 'LIST' then
                           ' values(' || sphval || ')'
                          else
                           null
                        end
                     end as sp_key,
                     t4.*,
                     t5.*
                from t4, t5),
            t7 as
             (select lag(p_key) over(order by partition_position, subpartition_position) as lg_pkey,
                     sp_key,
                     partition_position,
                     count(*) over() as cnt,
                     row_number() over(order by partition_position, subpartition_position) row_cnt,
                     count(subpartition_position) over(partition by partition_position) spcnt,
                     subpartition_position,
                     p_key,
                     part_col
                from t6),
            t8 as
             (select case
                       when p_key = lg_pkey then
                        null
                       else
                        p_key
                     end as p_key,
                     t7.sp_key,
                     t7.cnt,
                     t7.row_cnt,
                     t7.spcnt,
                     t7.partition_position,
                     t7.subpartition_position,
                     t7.part_col
                from t7)
            select regexp_replace(regexp_replace(case
                                                   when p_key is not null then
                                                    p_key || chr(10) || '('
                                                   else
                                                    null
                                                 end || case
                                                   when row_cnt = cnt then
                                                    sp_key || ')' || chr(10)
                                                   when spcnt = subpartition_position then
                                                    sp_key || '),' || chr(10)
                                                   else
                                                    sp_key || ',' || chr(10)
                                                 end,
                                                 '[(] subpartition ,$',
                                                 ','),
                                  '[(] subpartition [)]$') key_list,
                   t8.part_col bulk collect
              into v_part
              from t8
             order by partition_position, subpartition_position;
          exception
            when others then
              v_part := null;
          end;
          <<PartitionGeneratedBlock>>
        
          for loop_idx in 1 .. v_part.count loop
            v_partsql := v_partsql || v_part(loop_idx).col1;
          end loop;
        
          if v_part.count <> 0 then
         
            v_partsql := regexp_replace(v_part(1).col2,
                                        'subpartition by NONE[(][)]') ||
                         chr(10) || '(' || chr(10) || v_partsql || ')';
          else
            v_part := null;
          end if;
        
          /************************************************************************************/
          --将分区语句拼接到sql中
          v_ddl_stmt := v_ddl_stmt || v_partsql;
        
          dbms_output.put_line(v_ddl_stmt || ';');
          v_partsql := '';
        end loop;
      
      end convert_tab_create_ddl;

      procedure convert_index_create_ddl(in_tablist in varchar2) as
        /*
          Author: Zhangyu@BI
          CreateDate: 2014/05/14
          Version: 1.0Beta
          Function: convert oracle index create ddl to greenplum index create ddl.
        */
        v_idxlist dbms_sql.varchar2a;
        v_tablist dbms_sql.varchar2a;
      
      begin
        /************************************************************************************/
        --拆分参数存放入表清单数组
        /*
          格式必须为:
          owner.table_name
          或者
          owner table_name
        */
        v_tablist := metadata_ora2gp.split(in_tablist);
      
        for loop_idx in 1 .. v_tablist.count loop
        
          with t1 as
           (select di.owner,
                   di.index_name,
                   di.uniqueness,
                   di.index_type,
                   dic.COLUMN_NAME,
                   partitioned,
                   di.table_owner,
                   di.table_name,
                   dic.COLUMN_POSITION,
                   ' ' DESCEND --gp中无升降概念
              from dba_indexes di, dba_ind_columns dic
             where di.owner = dic.INDEX_OWNER
               and di.index_name = dic.INDEX_NAME
               and di.table_owner || '.' || di.table_name in
                   (upper(v_tablist(loop_idx)))
               and di.index_type not like 'FUNCTION-BASED%'),
          t2 as
           (select owner,
                   index_name,
                   uniqueness,
                   table_owner,
                   partitioned,
                   table_name,
                   index_type,
                   listagg(COLUMN_NAME || ' ' || DESCEND, ',') within group(order by COLUMN_POSITION) collist
              from t1
             group by owner,
                      index_name,
                      uniqueness,
                      index_type,
                      partitioned,
                      table_owner,
                      table_name)
          select 'create ' || case
                    when index_type = 'BITMAP' then
                    
                     index_type
                    when uniqueness = 'UNIQUE' then
                     uniqueness
                    else
                     null
                  end || ' index ' || t2.index_name || ' on ' ||
                  table_owner || '.' || t2.table_name || '(' || collist || ') ' ||
                 --dpi.locality
                  ';' as idx_crtsql bulk collect
            into v_idxlist
            from t2, dba_part_indexes dpi
           where t2.owner = dpi.owner(+)
             and t2.index_name = dpi.index_name(+);
        
          for loop_idx in 1 .. v_idxlist.count loop
            dbms_output.put_line(v_idxlist(loop_idx));
          end loop;
        
        end loop;
      
      end convert_index_create_ddl;

      procedure convert_constraint_ddl(in_tablist varchar2) as
        /*
          Author: Zhangyu@BI
          CreateDate: 2014/05/14
          Version: 1.0Beta
          Function: convert oracle index create ddl to greenplum index create ddl.
        */
        v_conslist dbms_sql.varchar2a;
        v_tablist dbms_sql.varchar2a;
      
      begin
        /************************************************************************************/
        --拆分参数存放入表清单数组
        /*
          格式必须为:
          owner.table_name
          或者
          owner table_name
        */
        v_tablist := metadata_ora2gp.split(in_tablist);
      
        for loop_idx in 1 .. v_tablist.count loop
        
          with t as
           (
            --check约束
            select 'alter table ' || dc.owner || '.' || dc.table_name ||
                    ' add constraint ' || dc.constraint_name || ' check (' ||
                    replace(dc.search_condition,'"') || ');' as cons_ddl
              from sys.my_constraints dc
             where dc.constraint_type in ('C')
               and dc.status = 'ENABLED'
               and dc.owner || '.' || dc.table_name = upper(v_tablist(loop_idx))
            union all
            --reference约束
            select 'alter table ' || dc.owner || '.' || dc.table_name ||
                    ' add constraint ' || dc.constraint_name || ' foreign key(' ||
                    collist || ') references ' || dc.r_owner || '.' ||
                    dc1.table_name || ';'
              from sys.my_constraints dc,
                    (select dcc.owner,
                            dcc.constraint_name,
                            dcc.table_name,
                            listagg(column_name, ',') within group(order by dcc.position) as collist
                       from dba_cons_columns dcc
                      group by dcc.owner, dcc.constraint_name, dcc.table_name) cons_col,
                    sys.my_constraints dc1
             where dc.constraint_type in ('R')
               and dc.status = 'ENABLED'
               and dc.owner = cons_col.owner
               and dc.table_name = cons_col.table_name
               and dc.constraint_name = cons_col.constraint_name
               and dc.r_owner = dc1.owner
               and dc.r_constraint_name = dc1.constraint_name
               and dc.owner || '.' || dc.table_name = upper(v_tablist(loop_idx))
            union all
            --unique约束
            select 'alter table ' || dc.owner || '.' || dc.table_name ||
                    ' add constraint ' || dc.constraint_name || ' unique(' ||
                    collist || ');'
              from sys.my_constraints dc,
                    (select dcc.owner,
                            dcc.constraint_name,
                            dcc.table_name,
                            listagg(column_name, ',') within group(order by dcc.position) as collist
                       from dba_cons_columns dcc
                      group by dcc.owner, dcc.constraint_name, dcc.table_name) cons_col
             where dc.constraint_type in ('U')
               and dc.status = 'ENABLED'
               and dc.owner = cons_col.owner
               and dc.table_name = cons_col.table_name
               and dc.constraint_name = cons_col.constraint_name
               and dc.owner || '.' || dc.table_name = upper(v_tablist(loop_idx))
            union all
            --primary约束
            select 'alter table ' || dc.owner || '.' || dc.table_name ||
                    ' add constraint ' || dc.constraint_name || ' primary key(' ||
                    collist || ');'
              from sys.my_constraints dc,
                    (select dcc.owner,
                            dcc.constraint_name,
                            dcc.table_name,
                            listagg(column_name, ',') within group(order by dcc.position) as collist
                       from dba_cons_columns dcc
                      group by dcc.owner, dcc.constraint_name, dcc.table_name) cons_col
             where dc.constraint_type in ('P')
               and dc.status = 'ENABLED'
               and dc.owner = cons_col.owner
               and dc.table_name = cons_col.table_name
               and dc.owner || '.' || dc.table_name = upper(v_tablist(loop_idx))
               and dc.constraint_name = cons_col.constraint_name)
          select * bulk collect into v_conslist from t;
        
          for loop_idx in 1 .. v_conslist.count loop
            dbms_output.put_line(v_conslist(loop_idx));
          end loop;
        end loop;
      
      end convert_constraint_ddl;
    end metadata_ora2gp;
    /



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-19735-1-1.html 上篇帖子: 10.2.0.1 RAC监听问题 下篇帖子: 11.2.0.4 RAC数据库存储迁移
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表