0

我有一个存储过程,它运行许多查询并获得许多存储在变量中的值。我希望这个过程能够将查询结果插入到用户提供的表中。我会将给定的表名存储为 varchar 参数,但如何插入到该表中?

在编译时,Oracle 说该表不存在。

4

2 回答 2

5

大概是在告诉您,您正在使用的变量名称的表不存在,当然它也不存在。实际的表在编译时可能存在也可能不存在;因为它很灵活,所以假设它可能不灵活可能更安全。无论哪种方式,您都不知道它将是什么,因此您需要使用动态 SQL 来实现这一点。

正如在另一个答案的评论中提到的,您必须小心 SQL 注入。通常您希望在动态 SQL 中使用绑定变量,但您不能对对象名称使用绑定,因此您必须将其连接起来。希望您使用的是包含dbms_assert软件包的 11g。

这是一个简单的例子:

create or replace procedure p42 (table_name varchar2) as
begin
  execute immediate 'insert into '
    || dbms_assert.qualified_sql_name(table_name)
    || ' select * from dual';
end;
/

然后我可以在过程已经存在后创建一个表,并成功调用该过程:

create table t42 (dummy varchar2(1));

exec p42('t42');

select * from t42;

DUMMY
-----
X     

您的实际查询显然会更复杂,并且应该对您传入的任何过滤器值以及目标表名称使用绑定变量。


调用的好处dbms_assert是如果传入了非法的东西,如果传入了一些讨厌的东西,它会出错:

exec p42('t42 select ''Y'' from dual union all');

ORA-44004: invalid qualified SQL name
ORA-06512: at "SYS.DBMS_ASSERT", line 207
ORA-06512: at "STACKOVERFLOW.P42", line 3
ORA-06512: at line 1

如果该过程只是连接传递的值:

  execute immediate 'insert into ' || table_name || ' select * from dual';

...然后相同的调用将在表中插入两行:

exec p42('t42 select ''Y'' from dual union all');

select * from t42;

DUMMY
-----
Y     
X

如果数据完整性对您来说很重要,那么您需要担心这一点。如果您不能使用dbms_assert,那么您可以尝试检查传递的名称是否确实存在all_tables并且不包含诸如union等之类的内容,但是承认您不会想到所有可能的攻击并让内置的-in 功能为您完成艰苦的工作。

于 2013-08-21T18:36:25.227 回答
0

尝试这样的事情:

exec ('insert into ' + @tblname + ' (col) values (123)')
于 2013-08-21T17:51:09.437 回答