【问题标题】:execute immediate ORA-00900立即执行 ORA-00900
【发布时间】:2016-10-09 20:54:15
【问题描述】:

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

让我们创建 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)

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

这意味着,使用一个脚本在比如说 insert.ddl 脚本中获取插入语句。

提前致谢:-)

【问题讨论】:

    标签: plsql oracle11g sqlplus


    【解决方案1】:

    您输入了太多(转义)引号。你从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)||')
    

    您还需要删除许多其他转义引号。

    【讨论】:

    • 谢谢亚历克斯。这肯定回答了我的问题和前面的许多疑问。
    【解决方案2】:

    如果您只想生成插入语句(不完全是这种方式),在 SQLDeveloper 中有一个函数,它可以生成插入语句。您只需要左键单击表>导出,然后取消选中“导出 DDL”。 Next> Next 和你有纯 SQL Insert 语句。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-21
      • 2021-12-22
      • 2018-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多