2016-06-09 109 views
1

我想从现有表中创建插入语句。但是,我最终面临着ORA-00900的问题。令人惊讶的是,当我使用execute immediate独立执行结果时,它工作正常。立即执行ORA-00900

让我们创建2个表:

create table a (
name varchar2 (100), 
age integer 
); 
insert into a values ('Tom', 1); 
commit; 
insert into a values ('John', 2); 
commit; 

create table b (
name varchar2 (100), 
age integer 
); 
insert into b values ('Jane', 1); 
commit; 
insert into b values ('Eric', 2); 
commit; 

现在,这里是我的工作得到的数据块。该块将使用SQL Plus。命令行参数将是:

SQL> @export.ddl my_schema a,b 

现在,我不写SET陈述在这里。

/* export.ddl */ 
declare 
    p_schema_name varchar2(1000) := upper('&1'); 
    p_table_names varchar2(4000) := upper('&2'); 
    l_statement varchar2(30000); 
    type tmp_table is table of varchar2(30000); 
    l_result tmp_table; 

begin 
    for c_table in ( 
    select 
     regexp_substr (replace(p_table_names, ' ', ''), '[^,]+', 1, level) as t_name 
    from dual 
    connect by 
     regexp_substr (replace(p_table_names, ' ', ''), '[^,]+', 1, level) is not null) 
    loop 
    for c_col in (
     select 
     '''select '''||ins.insert_stmt||'('||recs.select_rows||''')'''' stmt from '||recs.owner||'.'||recs.table_name||'''' as statement 
     from ( 
     select 
      atc.owner, 
      atc.table_name, 
      ''||listagg(case when atc.data_type = 'VARCHAR2' then '''''||decode('||atc.column_name||', null, ''''null'''', ''''''''''''''''||'||atc.column_name||'||'''''''''''''''')||''' 
          when atc.data_type = 'NUMBER' then '''''||decode('||atc.column_name||', null, ''''null'''', '||atc.column_name||')||''' 
          when atc.data_type = 'DATE' then 'to_date(''''''||to_char('||atc.column_name||', ''DD-MON-YYYY HH24:MI:SS'')||'''''', ''''DD-MON-YYYY HH24:MI:SS'''')' 
         end, ''', ') within group (order by atc.column_id) as select_rows 
     from dba_tab_columns atc 
     where atc.table_name in (c_table.t_name) -- here 
     group by atc.owner, atc.table_name) recs, 
     ( 
     select 
      atc.owner, 
      atc.table_name, 
      '''insert into '||atc.owner||'.'||atc.table_name||' ('||listagg(atc.column_name, ', ') within group (order by atc.column_id)||') VALUES ' as insert_stmt 
     from all_tab_columns atc 
     where atc.table_name in (c_table.t_name) -- here 
     group by atc.owner, atc.table_name 
    ) ins 
     where recs.owner = ins.owner 
     and recs.table_name = ins.table_name) 
    loop 
     l_statement := c_col.statement; 
     dbms_output.put_line(l_statement); 
     execute immediate l_statement bulk collect into l_result; 
     for i in 1 .. l_result.count() loop 
      dbms_output.put_line(l_result(i)); 
     end loop; 
    end loop; 
    end loop; 
end; 

在这段代码我的脸:

ORA-00900: invalid SQL statement 
ORA-06512: at line 44 

这是立即执行的语句的行号。

但是,如果我只复制DBMS_OUTPUT(注释掉执行即时发言和下面的循环),它是:

'select ''insert into MY_SCHEMA.A (NAME, AGE) VALUES (''||decode(NAME, null, ''null'', ''''''''||NAME||'''''''')||'', ''||decode(AGE, null, ''null'', AGE)||'')'' stmt from MY_SCHEMA.A' 
'select ''insert into MY_SCHEMA.B (NAME, AGE) VALUES (''||decode(NAME, null, ''null'', ''''''''||NAME||'''''''')||'', ''||decode(AGE, null, ''null'', AGE)||'')'' stmt from MY_SCHEMA.B' 

而且使用它像:

/* second.ddl */ 
declare 
    l_statememt varchar2(30000); 
    type typ_varcharlist IS TABLE OF VARCHAR2(30000); 
    col_list typ_varcharlist; 
    statemement varchar2(30000) := 'select ''insert into MY_SCHEMA.A (NAME, AGE) VALUES (''||decode(NAME, null, ''null'', ''''''''||NAME||'''''''')||'', ''||decode(AGE, null, ''null'', AGE)||'')'' stmt from MY_SCHEMA.A'; 
begin 
    execute immediate statemement bulk collect into col_list; 
    for i in 1 .. col_list.count() loop 
     dbms_output.put_line(col_list(i)); 
    end loop; 
end; 

然后我得到所需要的输出它是:

insert into MY_SCHEMA.A (NAME, AGE) VALUES ('Tom', 1) 
insert into MY_SCHEMA.A (NAME, AGE) VALUES ('John', 2) 

我的问题是: 为什么执行imm ediate在第一个代码(export.ddl)中给我错误?我能做些什么来阻止它,并从第二步(second.ddl)中拯救我自己?

这意味着,使用一个脚本来获取insert语句,比如insert.ddl脚本。

在此先感谢:-)

回答

2

您正在输入太多(转义)的引号。你从dbms_output看到生成的语句是

'select ''insert into MY_SCHEMA.A (NAME, AGE) VALUES (''||decode(NAME, null, ''null'', ''''''''||NAME||'''''''')||'', ''||decode(AGE, null, ''null'', AGE)||'')'' stmt from MY_SCHEMA.A' 

当您运行在你的第二块你把它当作一个字符串,当你把它分配给statemement变量 - 和分配取消转义所有的转义引号, 有效。当您在第一个块中直接运行它时,开始和结束引号无效。或者换一种说法,复制该输出(包括那些引号)并将其作为SQL语句直接粘贴到SQL * Plus中 - 那么您将查看ORA-00900。

只删除最外面的是不够的;只有那些被删除的,i.er.改变

'''select '''||ins.insert_stmt||'('||recs.select_rows||''')'''' stmt from '||recs.owner||'.'||recs.table_name||'''' as statement 

'select '''||ins.insert_stmt||'('||recs.select_rows||''')'' stmt from '||recs.owner||'.'||recs.table_name||'' as statement 

...它得到 “ORA-00923:FROM关键字未找到预期”。为了摆脱,你需要从insert_smt去除多余的报价,当关闭之前stmt

'select '''||ins.insert_stmt||'('||recs.select_rows||''')'' stmt from '||recs.owner||'.'||recs.table_name||'' as statement 

 'insert into '||atc.owner||'.'||atc.table_name||' ('||listagg(atc.column_name, ', ') within group (order by atc.column_id)||') VALUES ' as insert_stmt 

...现在将运行,但不会产生输出你想:

PL/SQL procedure successfully completed. 

select 'insert into MYSCHEMA.A (NAME, AGE) VALUES (''||decode(NAME, null, ''null'', ''''''''||NAME||'''''''')||'', ''||decode(AGE, null, ''null'', AGE)||'')' stmt from MYSCHEMA.A 
insert into MYSCHEMA.A (NAME, AGE) VALUES ('||decode(NAME, null, 'null', ''''||NAME||'''')||', '||decode(AGE, null, 'null', AGE)||') 
insert into MYSCHEMA.A (NAME, AGE) VALUES ('||decode(NAME, null, 'null', ''''||NAME||'''')||', '||decode(AGE, null, 'null', AGE)||') 
select 'insert into MYSCHEMA.B (NAME, AGE) VALUES (''||decode(NAME, null, ''null'', ''''''''||NAME||'''''''')||'', ''||decode(AGE, null, ''null'', AGE)||'')' stmt from STACKOVERFLOW.B 
insert into MYSCHEMA.B (NAME, AGE) VALUES ('||decode(NAME, null, 'null', ''''||NAME||'''')||', '||decode(AGE, null, 'null', AGE)||') 
insert into MYSCHEMA.B (NAME, AGE) VALUES ('||decode(NAME, null, 'null', ''''||NAME||'''')||', '||decode(AGE, null, 'null', AGE)||') 

您需要删除了很多其他的转义引号的了。

+0

谢谢亚历克斯。这当然回答了我的问题和许多问题。 – Jaanna

1

如果只想生成insert语句(不完全是这样),在的SQLDeveloper有一个函数,它生成的insert语句。您只需在表格>导出上左键单击,然后取消选中“导出DDL”。 Next> Next和您有纯SQL插入语句。