我可以使用DBMS_METADATA从DDL中剥离SUPPLEMENTAL LOG GROUP吗?

时间:2018-03-06 15:55:22

标签: sql oracle regexp-replace

我想获取表的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

如何摆脱SUPPLEMENTAL 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, 
...

2 个答案:

答案 0 :(得分:3)

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

fetch_ddl过程为您提供了各个DDL语句的嵌套表;并且您可以将其与set_transform_param()调用相结合,将约束拉出为alter语句 - 这也适用于补充日志子句。您还可以将表名更改为提取调用的一部分,而不是稍后使用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调用来改变它们。也可以。

答案 1 :(得分:1)

我相信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');`