我正在尝试从表中提取数据。多个表的名称可以逗号分隔值(如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
我做错了什么?
答案 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 *查询输出。我想你需要有一个引用光标,无论如何使用它。如果循环遍历多个表,根据您的代码,输出将始终被下一个表覆盖,因此您将仅获得最后一个查询输出。 所以对于这个假脱机文件中的输出并迭代到下一个表。
希望此信息有所帮助。