Return 从存储函数更新行
Return updated rows from a stored function
我正在尝试 select 来自 ORACLE Table 的一些行,同时更新 selected 行状态。我找到了一种使用存储函数和游标来执行此操作的方法,但在使用游标更新后我无法管理 return 行。这是我的代码:
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;
更新正在运行,但我仍然不知道如何return 游标中更新的行 (c_operations)。
谢谢。
我要做一些假设:
id_table1
是 table 的主键,所以你的 RBAR (*) 更新只影响一行
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()
函数将集合转换为 table 可以在引用游标中查询。
最后一点是我选择使用 sys.odcinumberlist
而不是在过程中定义集合的原因。它是 SQL 类型,所以我们可以在 SELECT 语句中使用它。
(*) 逐行痛苦。在 PL/SQL 循环中更新单个记录是执行批量更新最慢的方式,通常构成反模式。一个简单的基于集合的更新应该就足够了。但是,您知道自己的情况,所以我将保持原样。
在我看来你不需要初始游标,因为你正在将不是 'OK' 的每一行的状态更改为 'OK',所以你可以这样做一个简单的更新语句。然后使用 OPEN...FOR
语句 return STATUS 不是 'OK'
的所有行的游标,这不应该 return 任何东西,因为您已经更改了所有状态值至 '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;
与其循环更新,不如批量更新收集更新后的 ID。然后是来自那些返回的 id 的 table 函数。
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 ;
我正在尝试 select 来自 ORACLE Table 的一些行,同时更新 selected 行状态。我找到了一种使用存储函数和游标来执行此操作的方法,但在使用游标更新后我无法管理 return 行。这是我的代码:
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;
更新正在运行,但我仍然不知道如何return 游标中更新的行 (c_operations)。
谢谢。
我要做一些假设:
id_table1
是 table 的主键,所以你的 RBAR (*) 更新只影响一行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()
函数将集合转换为 table 可以在引用游标中查询。
最后一点是我选择使用 sys.odcinumberlist
而不是在过程中定义集合的原因。它是 SQL 类型,所以我们可以在 SELECT 语句中使用它。
(*) 逐行痛苦。在 PL/SQL 循环中更新单个记录是执行批量更新最慢的方式,通常构成反模式。一个简单的基于集合的更新应该就足够了。但是,您知道自己的情况,所以我将保持原样。
在我看来你不需要初始游标,因为你正在将不是 'OK' 的每一行的状态更改为 'OK',所以你可以这样做一个简单的更新语句。然后使用 OPEN...FOR
语句 return STATUS 不是 'OK'
的所有行的游标,这不应该 return 任何东西,因为您已经更改了所有状态值至 '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;
与其循环更新,不如批量更新收集更新后的 ID。然后是来自那些返回的 id 的 table 函数。
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 ;