从存储的函数返回更新的行

问题描述 投票:1回答:3

我正在尝试从ORACLE中的表中选择一些行,同时更新所选行的状态。我找到了一种使用存储的函数和游标执行此操作的方法,但是在使用游标进行更新后我无法设法返回行。这是我的代码:

CREATE OR REPLACE FUNCTION FUNCTION_NAME
   RETURN SYS_REFCURSOR
IS
   l_return   SYS_REFCURSOR;

    CURSOR c_operations IS
        SELECT * FROM TABLE1
        WHERE STATUS != 'OK'
        FOR UPDATE OF TABLE1.STATUS;

BEGIN

    FOR r_operation IN c_operations
    LOOP

        UPDATE
            TABLE1
        SET
            TABLE1.STATUS = 'OK'
        WHERE
            TABLE1.ID_TABLE1 = r_operation.ID_TABLE1;

    END LOOP;

    COMMIT;      

    -- Missing conversion from cursor to sys_refcursor

    RETURN l_return;

END;

该更新正在运行,但是我仍然缺少如何返回游标中更新后的行(c_operations)。

谢谢。

oracle stored-procedures plsql stored-functions
3个回答
1
投票

我要作一些假设:

  1. id_table1是表的主键,因此您的RBAR (*)更新仅影响一行
  2. id_table1是数字

如果这些假设是错误的,则需要调整以下代码。

CREATE OR REPLACE FUNCTION FUNCTION_NAME
   RETURN SYS_REFCURSOR
IS
   l_return   SYS_REFCURSOR;

   l_id       table1.id_table1%type;
   l_upd_ids  sys.odcinumberlist := new sys.odcinumberlist();

   CURSOR c_operations IS
        SELECT * FROM TABLE1
        WHERE STATUS != 'OK'
        FOR UPDATE OF TABLE1.STATUS;

BEGIN

    FOR r_operation IN c_operations   LOOP

        UPDATE TABLE1
        SET    TABLE1.STATUS = 'OK'
        WHERE  TABLE1.ID_TABLE1 = r_operation.ID_TABLE1
        returning TABLE1.ID_TABLE1 into l_id;

        l_upd_ids.extend();
        l_upd_ids(l_upd_ids.count()) := l_id;

    END LOOP;

    COMMIT;      

    open l_return for
        select * from table(l_upd_ids);

    RETURN l_return;

END;

解决方案的关键点。

  • 使用Oracle维护的(数量)sys.odcinumberlist集合来存储更新的ID;
  • 使用RETURNING子句捕获更新后的行的id_table1值;
  • 将返回的键存储在集合中;
  • 使用table()函数将集合简化为一个表,可以在引用游标中查询该表。

最后一点是为什么我选择使用sys.odcinumberlist而不是在过程中定义一个集合的原因。这是一种SQL类型,因此我们可以在SELECT语句中使用它。


(*)逐行进行。在PL / SQL循环中更新单个记录是执行批量更新的最慢方法,通常构成一种反模式。一个简单的基于集合的UPDATE就足够了。但是,您知道自己的处境,所以我将保持现状。


0
投票

在我看来,您不需要初始光标,因为您正在将不是'OK'的每一行的STATUS更改为'OK',因此您可以执行此操作,这是一个简单的UPDATE语句。然后使用OPEN...FOR语句返回状态不是'OK'的所有行的游标,因为您已经将所有状态值更改为'OK',所以该游标不应该返回任何内容。我建议您将过程重写为:

CREATE OR REPLACE FUNCTION FUNCTION_NAME
   RETURN SYS_REFCURSOR
IS
  l_return   SYS_REFCURSOR;
BEGIN
  UPDATE TABLE1
    SET STATUS = 'OK'
    WHERE STATUS != 'OK';

  COMMIT;      

  OPEN l_return FOR SELECT *
                      FROM TABLE1
                      WHERE STATUS != 'OK'
                      FOR UPDATE OF TABLE1.STATUS;

  RETURN l_return;
END;

0
投票

而不是循环来更新批量更新收集更新的ID的方式。然后从这些返回的id中创建表函数。

create type t_table1_id is
   table of integer;

create or replace function set_table1_status_ok
   return sys_refcursor
is 
    l_results_cursor sys_refcursor;
    l_updated_ids    t_table1_id;
begin
    update table1
       set status  = 'Ok'
     where status != 'Ok'
    returning table1.id 
       bulk collect
       into l_updated_ids;

    open l_results_cursor for
         select * 
           from table1 
          where id in (select * from table(l_updated_ids));
    return l_results_cursor;
end set_table1_status_ok;

-- test 
declare 
   updated_ids sys_refcursor;
   l_this_rec  table1%rowtype; 
begin
    updated_ids := set_table1_status_ok();

    loop 
        fetch updated_ids into l_this_rec;
        exit when updated_ids%notfound;
        dbms_output.put_line ( l_this_rec.id || ' updated.');
    end loop;
    close updated_ids;
end ;
© www.soinside.com 2019 - 2024. All rights reserved.