Oracle pl sql 动态使用子句
Posted
技术标签:
【中文标题】Oracle pl sql 动态使用子句【英文标题】:Oracle pl sql dynamic using clause 【发布时间】:2015-04-17 14:50:53 【问题描述】:我对执行立即语句中的“动态使用子句”有疑问。我还需要动态设置“执行立即语句”和 using 子句。不知道表结构,只知道表名,需要对其进行操作更新。
所以我写了一个函数(通过 user_tab_columns 和 user user_constraints 表)来使用 update 语句和 bind_variable 设置一个变量,但现在我需要使用变量列表设置 using 子句。
例子:
CREATE TABLE table1
(
rec1 VARCHAR2(10 BYTE) NULL,
rec2 DATE NULL,
rec3 number(9) not null
);
declare
TYPE cur_type IS REF CURSOR;
cur cur_type;
table_list table1%ROWTYPE;
sqlstring varchar2(400);
begin
OPEN cur FOR sqlstring;
LOOP
FETCH cur INTO table_list;
EXIT WHEN cur%NOTFOUND;
sqlstring:=function1('table1');
-- that returns sqlstring:='update table1 set rec1=:1 , rec2=:2 , rec3=:3 where rec_id=:c4';
execute immediate sqlstring using table_list.rec1, table_list.rec2, table_list.rec3, table_list.rec_id;
END LOOP;
close cur;
end;
我需要动态实现游标table_list的变量列表。
"使用 table_list.rec1、table_list.rec2、table_list.rec3、table_list.rec_id 执行立即 sqlstring"
有人知道如何解决这个问题吗?
【问题讨论】:
function1
的功能如何。我认为您必须使用 DBMS_SQL
已经存在的包,而不是返回一个简单的语句。
您所显示的内容实际上有什么问题 - 您是否得到错误或错误的结果?
你从哪里得到“table_list.rec_id”?它不是你的表结构的一部分
【参考方案1】:
非常感谢您的回复。
问题是我假设我不知道表的结构以及游标 table_list table1%ROWTYPE 的变量列表。 所以我不能在 using 子句中显式 table_list.rec1, table_list.rec2 ...。
如果我只使用 table_list 作为变量
begin
OPEN cur FOR sqlstring;
LOOP
FETCH cur INTO table_list;
EXIT WHEN cur%NOTFOUND;
sqlstring:=function1('table1');
execute immediate sqlstring using table_list;
END LOOP;
close cur;
我收到错误:“00457 表达式必须是 SQL 类型”
http://psoug.org/oraerror/PLS-00457.htm
错误原因: 错误类型的表达式在 USING 或动态 RETURNING 子句中。在 USING 或动态 RETURNING 子句中,表达式不能是非 SQL 类型,如 BOOLEAN、INDEX TABLE 和记录。
我需要一种方法来首先检索游标 table_list 的值和变量列表。 但也许这是不可能的,我必须找到解决办法。
如果我发现一些有趣的东西,我会发布。 谢谢。
【讨论】:
【参考方案2】:尝试将您的执行立即替换为充分使用 dbms_sql。 http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_sql.htm#i996891
这个包中的 bind_array 函数对你有用。
【讨论】:
【参考方案3】:使用动态 PL/SQL,除非您可以重构原始语句并将值插入其中。
declare
v_string constant varchar2(32767) := 'update test1 set a = :1, b = :2';
v_using_string varchar2(32767);
begin
--Create dynamic using string.
--For example, let's say you want to pass in the values "1" for each NUMBER column.
select listagg(1, ',') within group (order by null)
into v_using_string
from user_tab_columns
where table_name = 'TEST1'
and data_type = 'NUMBER';
--Execute the original dynamic SQL, adding the USING string.
execute immediate '
begin
execute immediate '''||v_string||''' using '||v_using_string||';
end;
';
end;
/
【讨论】:
【参考方案4】:您可以使用DBMS_SQL
包:
-
使用
dbms_sql.open_cursor
打开游标
使用dbms_sql.parse
解析语句
使用dbms_sql.bind_variable
在循环中绑定变量
使用dbms_sql.execute
执行语句
最后使用dbms_sql.close_cursor
关闭光标
或者EXECUTE IMMEDIATE
的匿名PL/SQL块,执行动态创建的EXECUTE IMMEDIATE
(这种方式不适合返回数据)。请参阅@JonHeller 的回答。
【讨论】:
以上是关于Oracle pl sql 动态使用子句的主要内容,如果未能解决你的问题,请参考以下文章
SQL 查询的 SELECT 子句中 Oracle PL/SQL 语句的延迟评估
Oracle PL/SQL:在 SAMPLE 子句中使用变量时出现语法错误
变量作为 Oracle PL/SQL 中 where 子句中的列名
如何在 select 的 where 子句中替换 oracle pl/sql 变量