Sql 将查询结果插入到由变量命名的表中

Sql 将查询结果插入到由变量命名的表中,sql,oracle,variables,Sql,Oracle,Variables,我有一个存储过程,它运行许多查询,并获取许多存储在变量中的值。我希望这个过程能够将查询结果插入到用户给定的表中。我会将给定的表名存储为varchar参数,但如何将其插入到该表中 在编译时,Oracle表示该表不存在。请尝试以下操作: exec ('insert into ' + @tblname + ' (col) values (123)') 试着这样做: exec ('insert into ' + @tblname + ' (col) values (123)') 它可能会告诉您,使用

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


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

请尝试以下操作:

exec ('insert into ' + @tblname + ' (col) values (123)')

试着这样做:

exec ('insert into ' + @tblname + ' (col) values (123)')

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

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

下面是一个简单的例子:

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\u 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\u assert
,那么您可以尝试检查传递的名称是否确实存在于
所有表中,并且不包含任何类似于
联合等的内容。但是,更安全的做法是,您不会想到所有可能的攻击,而是让内置函数为其进行艰苦的工作您。

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

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

下面是一个简单的例子:

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\u 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\u assert
,那么您可以尝试检查传递的名称是否确实存在于
所有表中,并且不包含任何类似
union
等的内容。但更安全的是,您不会想到所有可能的攻击,而是让内置函数为您做艰苦的工作。

错,但这种方法“可能”存在一些SQL注入问题。通常,如果从用户那里获取整个语句,SQL注入就是一种威胁。这里只是表名。不管怎样,这是一个插入。
@tblName
从哪里设置或传递?参数周围的语句类型没有区别;重要的是如何使用参数和执行语句。例如,如果可以通过用户输入设置
@tblname
,则该语句可用于SQL注入。我想举一个如何使用该语句的示例。说真的。在Oracle中,您需要
立即执行
。我可能错了,但这种方法“可能”存在一些SQL注入问题。通常,如果您从用户那里获取整个语句,SQL注入就是一种威胁。这里只是表名。不管怎样,这是一个插入。
@tblName
从哪里设置或传递?参数周围的语句类型没有区别;重要的是如何使用参数和执行语句。例如,如果可以通过用户输入设置
@tblname
,则该语句可用于SQL注入。我想举一个如何使用该语句的示例。说真的。在Oracle中,您需要
立即执行