Oracle FORALL和sql%rowcount(当FORALL从未输入时)
我很好奇你们是如何处理这样一个问题的:Oracle FORALL和sql%rowcount(当FORALL从未输入时),oracle,plsql,bulk-operations,Oracle,Plsql,Bulk Operations,我很好奇你们是如何处理这样一个问题的:sql%rowcount在一个根本没有输入的FORALL之后没有设置。下面我如何解决它的示例(使用变量v_rowcount和FORALL所基于的集合的count)。但我觉得有一种更聪明的方法: create table tst (id number); -- we start with an empty table declare type type_numbers is table of number; v_numbers type_nu
sql%rowcount
在一个根本没有输入的FORALL
之后没有设置。下面我如何解决它的示例(使用变量v_rowcount
和FORALL
所基于的集合的count
)。但我觉得有一种更聪明的方法:
create table tst (id number); -- we start with an empty table
declare
type type_numbers is table of number;
v_numbers type_numbers;
v_rowcount number;
begin
insert into tst values (1);
DBMS_OUTPUT.put_line(sql%rowcount); -- prints 1 which is correct, 1 row inserted
delete from tst;
DBMS_OUTPUT.put_line(sql%rowcount); -- prints 1 which is correct, 1 row deleted
v_numbers := type_numbers(3,4,5);
forall v in 1 .. v_numbers.count
update tst
set id = v_numbers(v)
where id = v_numbers(v);
DBMS_OUTPUT.put_line(sql%rowcount); -- prints 0 which is correct, 0 rows updated
insert into tst values (1);
DBMS_OUTPUT.put_line(sql%rowcount); -- prints 1 which is correct, 1 row inserted
delete from tst;
DBMS_OUTPUT.put_line(sql%rowcount); -- prints 1 which is correct, 1 row deleted
v_numbers := type_numbers();
forall v in 1 .. v_numbers.count
update tst
set id = v_numbers(v)
where id = v_numbers(v);
DBMS_OUTPUT.put_line(sql%rowcount); -- prints 1 which is WRONG, 0 rows updated (this is still the sql%rowcount of the DELETE above)
forall v in 1 .. v_numbers.count
update tst
set id = v_numbers(v)
where id = v_numbers(v);
v_rowcount := 0;
if v_numbers.count > 0 then
v_rowcount := sql%rowcount;
end if;
DBMS_OUTPUT.put_line(v_rowcount); -- prints 0 which is correct, 0 rows updated
end;
/
SQL%ROWCOUNT与FORALL一起使用 请参见下面的示例:
-- Data preparation
CREATE TABLE EMPLOYEES (
EMPID NUMBER,
EMPNAME VARCHAR2(100)
);
INSERT INTO EMPLOYEES VALUES (
1,
'a'
);
INSERT INTO EMPLOYEES VALUES (
2,
'b'
);
INSERT INTO EMPLOYEES VALUES (
3,
'c'
);
INSERT INTO EMPLOYEES VALUES (
4,
'a'
);
INSERT INTO EMPLOYEES VALUES (
5,
'e'
);
SELECT * FROM EMPLOYEES;
因此,根据我的示例,它存储了SQL%ROWCOUNT中受影响的许多行,即使我们使用FORALL。---但是,如果我在“DELETE”语句之后删除“COMMIT”,那么我也将面临与您描述的相同的问题
因此,问题的解决方案是COMMIT
语句。尝试在delete之后使用commit语句运行代码
希望这对你有用
已更新
BEGIN
OPEN C_DATA;
FETCH C_DATA BULK COLLECT INTO L_TAB;
FORALL I IN 1..L_TAB.COUNT
UPDATE EMPLOYEES
SET
EMPNAME = L_TAB(I).EMPNAME || L_TAB(I).EMPNAME
WHERE
EMPID = L_TAB(I).EMPID;
DBMS_OUTPUT.PUT_LINE('1) SQL%ROWCOUNT IS ' || SQL%ROWCOUNT);
CLOSE C_DATA;
DELETE FROM EMPLOYEES;
DBMS_OUTPUT.PUT_LINE('2) SQL%ROWCOUNT IS ' || SQL%ROWCOUNT);
SAVEPOINT A; --- IMP
OPEN C_DATA;
FETCH C_DATA BULK COLLECT INTO L_TAB;
FORALL I IN 1..L_TAB.COUNT
UPDATE EMPLOYEES
SET
EMPNAME = L_TAB(I).EMPNAME || L_TAB(I).EMPNAME
WHERE
EMPID = L_TAB(I).EMPID;
DBMS_OUTPUT.PUT_LINE('3) SQL%ROWCOUNT IS ' || SQL%ROWCOUNT);
CLOSE C_DATA;
END;
/
我会像你的例子那样做,但也有其他选择。我们可以使用
sql%bulk\u rowcount
,这对于forall
可能更好。下面是Oracle文档和一些示例。这是我的测试表:
create table test (id, val) as (
select 1, 'PQR' from dual union all
select 2, 'AB1' from dual union all
select 2, 'AB2' from dual union all
select 3, 'XYZ' from dual );
和示例代码块,其中我使用了短函数求和bulk\u rowcount
s:
declare
type t is table of number;
a t;
function bulkcount(x in t) return number is
ret number := 0;
begin
for i in 1..x.count loop
ret := ret + sql%bulk_rowcount(i);
end loop;
return ret;
end bulkcount;
begin
a := t(2, 3, 7);
forall i in a.first..a.last
delete from test where id = a(i);
dbms_output.put_line('sql rowcount: '||sql%rowcount);
dbms_output.put_line('sum of bull_rowcount: '||bulkcount(a));
a := t();
forall i in a.first..a.last
update test set val = 'ZZZ' where id = a(i);
dbms_output.put_line('sql rowcount: '||sql%rowcount);
dbms_output.put_line('sum of bull_rowcount: '||bulkcount(a));
end;
结果:
sql rowcount: 3
sum of bull_rowcount: 3
sql rowcount: 3 -- "wrong", value from previous DML
sum of bull_rowcount: 0
sql%rowcount
是上次dml的结果。未执行forall循环中的update,因此sql%rowcount
显示delete语句的结果。怎么了?@hotfix谢谢。没问题。我只是好奇如何很好地处理这种情况。如果v_numbers.count>0,我用的解决方案对我来说似乎很笨拙,甚至可能产生错误的结果(想不出一个例子)。我不太明白问题是什么。为什么不先检查集合是否为空?@hotfix这正是我的问题:-)这里的最佳做法是什么?在论坛之前检查收藏数量的最佳做法是什么?@hotfix-是的,EBKAC。嗨,谢谢。是sql%rowcount适用于FORALL,但仅当pl/sql集合不为空时。在您的示例中,l_选项卡包含5个对象。在我的示例中,集合不包含任何对象,因此未设置sql%rowcount。我的问题是如何在集合为空的FORALL之后处理sql%rowcount。看我的例子。泰。krI已根据您的要求更新了我的答案。请使用您的代码进行检查和测试。谢谢,但我不想仅为了sql%rowcount正确而提交:-)完美,我只是解释为什么它不工作。如果对你有用的话,我会给出解决方案。我已经更新了答案。只需使用保存点
。无需提交
。会有用的,谢谢!我知道你会和我的例子一样。和你一样,我也认为bulk_rowcount
对于我的示例来说是一种过分的杀伤力,尤其是它与我的空集合示例所做的事情完全相同ret number:=0;[…]对于1..x.count循环中的i[…]未输入循环…]结束循环;返回ret
对我来说等于我所做的v_rowcount:=0;如果v_numbers.count>0,则[…未输入…]如果结束;DBMS_OUTPUT.put_行(v_rowcount)代码>如果集合为空,则两个版本都返回数字0,而不检查任何sql%参数。是bulk\u rowcount
是一个有趣的替代方案,它允许您为集合的每个元素查找受影响的行数,而rowcount
和forall
是不可能的。但在这里我会使用你的版本。
declare
type t is table of number;
a t;
function bulkcount(x in t) return number is
ret number := 0;
begin
for i in 1..x.count loop
ret := ret + sql%bulk_rowcount(i);
end loop;
return ret;
end bulkcount;
begin
a := t(2, 3, 7);
forall i in a.first..a.last
delete from test where id = a(i);
dbms_output.put_line('sql rowcount: '||sql%rowcount);
dbms_output.put_line('sum of bull_rowcount: '||bulkcount(a));
a := t();
forall i in a.first..a.last
update test set val = 'ZZZ' where id = a(i);
dbms_output.put_line('sql rowcount: '||sql%rowcount);
dbms_output.put_line('sum of bull_rowcount: '||bulkcount(a));
end;
sql rowcount: 3
sum of bull_rowcount: 3
sql rowcount: 3 -- "wrong", value from previous DML
sum of bull_rowcount: 0