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 变量

通过添加嵌入在 PL-SQL(Oracle 函数)中的 select 子句来处理异常

WITH子句中的PL/SQL