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

Posted

技术标签:

【中文标题】在循环中立即执行获取表数据【英文标题】:Getting table data with execute immediate in a loop 【发布时间】:2016-06-07 11:16:22 【问题描述】:

我正在尝试从表中提取数据。多个表的名称可以以逗号分隔值(如 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

我哪里做错了?

【问题讨论】:

【参考方案1】:

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

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

...
begin
  p_statement := 'select * from ';
  ...
      execute immediate p_statement || p_schema_name ||'.'|| foo.txt;
  end loop;
end;

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

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

如果 dynamic_sql_statement 是一个 SELECT 语句,并且您省略了 into_clausebulk_collect_into_clause,那么 execute_immediate_statement 永远不会执行.

您需要将您的数据选择到某个东西中,如果可以传入的表具有不同的结构,这将是一件棘手的事情。如果您打算将查询的数据写入文件并且不知道结构,那么您需要使用the DBMS_SQL package 而不是execute immediate

【讨论】:

【参考方案2】:

表名和列名不能作为绑定变量传递给立即执行语句!

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

但是另一个错误是您缺少执行立即语句的 INTO 子句来处理其他贡献者所说的 SELECT 语句。

谢谢, 乙

【讨论】:

【参考方案3】:

根据您的问题,您将如何处理来自 PLSQL 的 SELECT * 查询的输出。我猜你要么需要一个参考光标才能使用它。同样根据您的代码,如果您遍历多个表,则输出将始终被下一个表覆盖,因此您将仅获得最后一个查询输出。 因此,对于这个假脱机,输出一个文件并迭代到下一个表。

希望这些信息对您有所帮助。

【讨论】:

以上是关于在循环中立即执行获取表数据的主要内容,如果未能解决你的问题,请参考以下文章

Vue.nextTick DOM 更新循环结束之后执行延迟回调

[Vue] vue的一些面试题4

this.$nextTick()

Vue的dom更新机制 & Vue的nextTick

vue2.0 之 nextTick

vue nexttick的理解和使用场景