在循环中使用执行立即获取表数据

时间:2016-06-07 11:16:22

标签: oracle plsql dynamic-sql

我正在尝试从表中提取数据。多个表的名称可以逗号分隔值(如a,b,c)给出,并根据我需要将数据提取到文件中。这是代码,它通过SQL * Plus运行:

declare 
  p_schema_name varchar2(1000) := '&1';
  p_table_names varchar2(4000) := '&2';
  p_statement varchar2(4000);
begin
  p_statement := 'select * from :x'||'.'||':y';
  for foo in (    
    select 
      regexp_substr (replace(p_table_names, ' ', ''), '[^,]+', 1, level) as txt
    from dual
    connect by 
      regexp_substr (replace(p_table_names, ' ', ''), '[^,]+', 1, level) is not null)
  loop
      execute immediate p_statement using p_schema_name, foo.txt;
  end loop;
end;

当我执行此脚本时,我收到以下错误:

ORA-00903: invalid table name
ORA-06512: at line 14

我做错了什么?

3 个答案:

答案 0 :(得分:3)

您只能绑定变量,而不能绑定对象名称。绑定替换在执行查询时完成,而不是在解析时完成。必须在解析时知道对象名称。

您必须将架构和表名称连接到查询中:

execute immediate

当然现在有SQL injection的潜力,所以你需要清理输入。您可以检查它们是否是有效名称,或者在尝试执行查询之前检查提取的表是否存在于指定的模式中。您可能会发现the DBMS_ASSERT package很有用。

虽然您的查询目前不会被执行; from the documentation

  

如果 dynamic_sql_statement 是SELECT语句,并且您省略了 into_clause bulk_collect_into_clause ,那么 execute_immediate_statement 永远不会执行

您需要将数据选择为某些内容,如果可以传入的表具有不同的结构,那将会很棘手。如果您计划将查询的数据写入文件但不知道结构,那么您需要使用the DBMS_SQL package而不是{{1}}。

答案 1 :(得分:1)

表名和列名不能作为Bind变量传递给Execute immediate语句!

而是将它们用作变量并将它们连接起来。

但是另一个错误是你错过了执行立即语句的INTO子句,处理SELECT语句,如另一个贡献者所说。

谢谢, 乙

答案 2 :(得分:1)

根据您的问题,您将如何处理来自PLSQL的SELECT *查询输出。我想你需要有一个引用光标,无论如何使用它。如果循环遍历多个表,根据您的代码,输出将始终被下一个表覆盖,因此您将仅获得最后一个查询输出。 所以对于这个假脱机文件中的输出并迭代到下一个表。

希望此信息有所帮助。