【问题标题】:Can I use DBMS_METADATA to strip off the SUPPLEMENTAL LOG GROUP from a DDL?我可以使用 DBMS_METADATA 从 DDL 中剥离 SUPPLEMENTAL LOG GROUP 吗?
【发布时间】:2018-03-07 02:14:21
【问题描述】:

我想获取一个表的 DDL 并从中创建另一个。目前我有这样的事情:

 v_stmt := 'select dbms_metadata.get_ddl(''TABLE'', ''' || original_table || ''') from dual';
 execute immediate v_stmt into v_stmt ;
 v_stmt := REGEXP_REPLACE(v_stmt, '(' || original_table || ')', new_table, 1, 1);
 execute immediate v_stmt;

当前表已生成 SUPPLEMENTAL LOG GROUP。我不想要这个,或者更确切地说,当我尝试创建时,我遇到了以下错误。

ORA-30567: name already used by an existing log group

如何摆脱补充日志组?是否可以使用类似下面的东西或有其他解决方案?

dbms_metadata.set_transform_param(dbms_metadata.session_transform,'PARTITIONING',false);

我想我也可以使用 REGEXP_REPLACE,但我也不知道该怎么做。

作为参考,生成的语句包含如下内容:

...
 SUPPLEMENTAL LOG GROUP "SCHEM_TAB0123434" ("CUSTOMERKEY", "VALID", "VERSION", "WHENMODIFIED") ALWAYS, 
...

【问题讨论】:

    标签: sql oracle regexp-replace


    【解决方案1】:

    您似乎无法完全摆脱它,但如果您使用不同的 dbms_metadata 子程序,您可以将补充日志记录子句拆分为单独的语句并跳过它们。

    fetch_ddl 过程为您提供了单个 DDL 语句的嵌套表;您可以将其与set_transform_param() 调用结合起来,将约束作为alter 语句提取出来——这也适用于补充日志子句。您还可以在 fetch 调用中更改表名,而不是稍后手动替换为 set_remap_param()

    如果我创建一个带有补充日志记录的虚拟表:

    create table t42 (
      id number,
      log_this varchar2(10),
      constraint pk_t42 primary key (id),
      supplemental log group t42_log_group (log_this) always
    );
    

    然后我可以打开一个上下文句柄,为表名应用过滤器,然后进行转换;然后遍历 DDL 并选择要使用的内容和要跳过的内容:

    set serveroutput on;
    
    declare
      l_original_table user_tables.table_name%type := 'T42';
      l_new_table user_tables.table_name%type := 'NEW_T42';
    
      l_context pls_integer;
      l_modify pls_integer;
      l_transform pls_integer;
      l_ddls sys.ku$_ddls;
      l_ddl clob;
    begin
      l_context := dbms_metadata.open('TABLE');
      -- to look for the specific table you are interested in
      dbms_metadata.set_filter(l_context, 'NAME', l_original_table);
    
      l_modify := dbms_metadata.add_transform(l_context, 'MODIFY');
      -- to change the table name in the generated DDL
      dbms_metadata.set_remap_param(l_modify, 'REMAP_NAME', l_original_table, l_new_table,
        'TABLE');
    
      l_transform := dbms_metadata.add_transform(l_context, 'DDL');
      -- for brevity
      dbms_metadata.set_transform_param(l_transform, 'SEGMENT_ATTRIBUTES', false);
      -- to split constraints and supplemental logging into separtate DDLs
      dbms_metadata.set_transform_param(l_transform, 'CONSTRAINTS_AS_ALTER', true);
    
      l_ddls := dbms_metadata.fetch_ddl(l_context);
    
      for i in l_ddls.first..l_ddls.last loop
        l_ddl := l_ddls(i).ddltext;
        if dbms_lob.instr(l_ddl, 'SUPPLEMENTAL LOG GROUP') > 0 then
          dbms_output.put_line('Skipping DDL: ' || dbms_lob.substr(l_ddl, 4000, 1));
          continue;
        end if;
    
        dbms_output.put_line('Using DDL: ' || dbms_lob.substr(l_ddl, 4000, 1));
        dbms_output.new_line;
    
        -- execute immediate l_ddl;
      end loop;
    
      dbms_metadata.close(l_context);
    end;
    /
    

    该虚拟表显示的内容:

    Using DDL: CREATE TABLE "MY_SCHEMA"."NEW_T42" 
       (    "ID" NUMBER, 
        "LOG_THIS" VARCHAR2(10)
       ) 
    
    Using DDL: 
      ALTER TABLE "MY_SCHEMA"."NEW_T42" ADD CONSTRAINT "PK_T42" PRIMARY KEY ("ID")
      USING INDEX  ENABLE
    
    Skipping DDL: 
      ALTER TABLE "MY_SCHEMA"."NEW_T42" ADD SUPPLEMENTAL LOG GROUP "T42_LOG_GROUP" ("LOG_THIS") ALWAYS
    
    
    PL/SQL procedure successfully completed.
    

    保留基本的create table,以及除与'SUPPLEMENTAL LOG GROUP' 字符串匹配的任何其他语句。

    在这种情况下,我的 PK 约束名称也将成为问题 - 第一个 create DDL 将在 execute immediate 未注释的情况下运行正常,但当前未被跳过的 alter 将得到 ORA-02264 .如果你有一个合理的命名约定,你可以添加额外的 set_remap_param 调用来改变它们,也许。

    【讨论】:

    • 是的,这与我的预期很接近。谢谢你的详细回答。
    【解决方案2】:

    我相信 SET_TRANSFORM_PARAM 在这里无济于事。
    您可以尝试使用 REGEXP_REPLACE:

    `v_stmt := regexp_replace(v_stmt, ',\s*supplemental\s+log\s+group\s+"[^"]+"\s*\("[^"]+"(,\s*"[^"]+")*\)\s*always\s*', '',1, 1,'i');`
    

    【讨论】:

    • 谢谢,上面语句中的“i”是什么意思?
    • @pna - 匹配不区分大小写。
    • 我确认,替换字符串''后的三个参数是位置、出现、正则表达式匹配模式,为了方便,后者是'i'(不区分大小写)。
    • 谢谢大家。但是,这只会删除第一次出现的补充日志组。我想删除所有出现的事件。
    • @pna 我希望你会接受 Alex 的回答,你确定吗?
    猜你喜欢
    • 2013-05-05
    • 2013-04-04
    • 1970-01-01
    • 2020-03-10
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 2011-07-22
    • 2011-06-10
    相关资源
    最近更新 更多