在EXECUTE IMMEDIATE中使用SQL时如何解决ORA-00984?

在EXECUTE IMMEDIATE中使用SQL时如何解决ORA-00984?,sql,oracle,plsql,oracle11g,Sql,Oracle,Plsql,Oracle11g,我正在尝试将预定义Oracle数据库管理用户帐户的lsit存储到一个表DBOMIT_SCHEMAS中,该表使用代码中的列表schema_list DECLARE TYPE schema_list_type IS TABLE OF "DBCONTROL"."DBSCHEMA_INFO".SCHEMA%TYPE; schema_list schema_list_type; BEGIN schema_list := schema_list_type('ANONYMOUS', 'CTXSYS

我正在尝试将预定义Oracle数据库管理用户帐户的lsit存储到一个表DBOMIT_SCHEMAS中,该表使用代码中的列表schema_list

DECLARE
  TYPE schema_list_type IS TABLE OF "DBCONTROL"."DBSCHEMA_INFO".SCHEMA%TYPE;
  schema_list schema_list_type;
BEGIN
  schema_list := schema_list_type('ANONYMOUS', 'CTXSYS', 'DBSNMP', 'EXFSYS', 'LBACSYS', 'MDSYS', 'MGMT_VIEW','OLAPSYS', 'OWBSYS', 'ORDPLUGINS', 'ORDSYS', 'OUTLN', 'SI_INFORMTN_SCHEMA', 'SYS', 'SYSMAN', 'SYSTEM', 'TSMSYS', 'WK_TEST', 'WKSYS', 'WKPROXY', 'WMSYS', 'XDB');

  FOR i IN schema_list.FIRST .. schema_list.LAST
  LOOP
    DBMS_OUTPUT.PUT_LINE('***DEBUG***: '||schema_list(i));
    EXECUTE IMMEDIATE('INSERT INTO "DBCONTROL"."DBOMIT_SCHEMAS" VALUES('||schema_list(i)||')');
  END LOOP;

END;

当我尝试循环遍历列表并将每个值插入到表中时,我得到ORA-00984:column not allowed here错误。我猜,这是因为它理解匿名(列名)而不是“匿名”(字符串)。任何人都可以解决此问题。

您不需要在此处立即执行,只需执行以下操作:

  LOOP
    DBMS_OUTPUT.PUT_LINE('***DEBUG***: '||schema_list(i));
    INSERT INTO "DBCONTROL"."DBOMIT_SCHEMAS" VALUES(schema_list(i));
  END LOOP;

您不需要在此处立即执行,只需执行以下操作:

  LOOP
    DBMS_OUTPUT.PUT_LINE('***DEBUG***: '||schema_list(i));
    INSERT INTO "DBCONTROL"."DBOMIT_SCHEMAS" VALUES(schema_list(i));
  END LOOP;

kodiko是对的,在这里您根本不需要动态SQL,也不应该使用它(因为不需要-更难编写,更难调试,…)。但对于您的实际错误,这是因为您使用的是硬编码字符串值,而没有将其括在引号中。您需要使用:

EXECUTE IMMEDIATE('INSERT INTO "DBCONTROL"."DBOMIT_SCHEMAS" VALUES('''
  ||schema_list(i)||''')');
这会将已执行SQL的结尾从
VALUES(匿名)
更改为
VALUES('ANONYMOUS')
。由于需要转义,额外的引号会加倍,这就是机制。(您可以使用另一种引用的语法,但在构建字符串时,我发现它没有那么明显的用处)

但您不应该硬编码值,应该使用绑定变量:

EXECUTE IMMEDIATE('INSERT INTO "DBCONTROL"."DBOMIT_SCHEMAS" VALUES(:id)')
USING schema_list(i);
在这种情况下,应该使用普通SQL,但如果必须使用动态SQL,则应该使用绑定变量


我还将丢失模式和表名周围的双引号,因为它们不需要被引用,所以它们实际上只是噪音。您还可以使用
forall
执行批插入,如果
类型是在模式级别声明的,那么您可以在没有循环的情况下在单个插入中执行此操作,但我想这是一个练习。

kodiko是对的,您根本不需要动态SQL,也不应该使用它(因为不需要-更难写,更难调试…)。但对于您的实际错误,这是因为您使用的是硬编码字符串值,而没有将其括在引号中。您需要使用:

EXECUTE IMMEDIATE('INSERT INTO "DBCONTROL"."DBOMIT_SCHEMAS" VALUES('''
  ||schema_list(i)||''')');
这将执行的SQL的结尾从
VALUES(ANONYMOUS)
更改为
VALUES('ANONYMOUS')
。由于需要转义,额外的引号会加倍,这就是机制。(您可以使用替代的引号语法,但在构建字符串时,我发现这不太有用)

但您不应该硬编码值,应该使用绑定变量:

EXECUTE IMMEDIATE('INSERT INTO "DBCONTROL"."DBOMIT_SCHEMAS" VALUES(:id)')
USING schema_list(i);
在这种情况下,应该使用普通SQL,但如果必须使用动态SQL,则应该使用绑定变量


我也会丢失模式和表名周围的双引号,因为它们不需要被引用,所以它们实际上只是噪音。您也可以使用
forall
进行批插入,如果
类型
是在模式级别声明的,那么您可以在没有循环的情况下在单个插入中进行此操作,但我想这是一个练习。

如果我使用纯SQL语句,我会得到ORA-06550:error。这是因为在插入值之前,我有一个EXECUTE IMMEDIATE语句来创建表。我尝试分离它们,效果很好。即使使用bind变量,我也会得到ORA-00911:invalid character error。它可以根据需要使用额外的引号。@Syam-是的,如果您正在创建表动态插入您是对的,插入也必须是动态的。(不过动态创建表是不寻常的)。您不需要在bind变量周围加引号;但是如果我使用Oracle
:var
语法而不是JDBC
语法,这将非常有帮助。如果您只是在其周围加引号,那么表中插入的所有值都将是
“?”
,而不是实际的架构名称。我已经更正(并测试了)很抱歉。当我使用纯SQL语句时,我得到ORA-06550:error。这是因为我在插入值之前有一个EXECUTE IMMEDIATE语句来创建表。我尝试分离它们,但效果很好。即使使用bind变量,我也得到ORA-00911:invalid character error。它可以根据我的需要使用额外的引号。@Syam-是的,如果您需要的话动态地重新创建表您是对的,插入也必须是动态的。您不需要在bind变量周围加引号;但是如果我使用Oracle
:var
语法而不是JDBC
语法,这将非常有帮助。如果您只是在其周围加引号,那么表中插入的所有值都将是
“?”
,而不是实际的架构名称。我已经更正(并测试了)那,对不起。