我很好奇你们如何处理在根本没有输入的sql%rowcount
之后没有设置FORALL
的问题。下面是我如何解决问题的示例(使用变量v_rowcount
和count
所基于的集合的FORALL
)。但是我有一种更聪明的方法:
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;
/
答案 0 :(得分:2)
我将按照您的示例进行操作,但是也有其他选择。我们可以使用sql%bulk_rowcount
,它可能更适合forall
。这是Oracle文档的link和一些示例。这是我的测试表:
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_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
答案 1 :(得分:0)
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;
-- FORALL update in the block
SET SERVEROUT ON
DECLARE
TYPE T_BULK_COLLECT_TEST IS
TABLE OF EMPLOYEES%ROWTYPE;
L_TAB T_BULK_COLLECT_TEST;
CURSOR C_DATA IS
SELECT
*
FROM
EMPLOYEES;
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);
COMMIT;
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;
/
-- Output after data is updated
SELECT * FROM EMPLOYEES;
因此,按照我的示例,即使我们使用FORALL,它也会存储SQL%ROWCOUNT中受影响的行数。 ----但是但是,如果我在'DELETE'语句之后删除'COMMIT',那么我也面临与您描述的相同的问题。
因此,解决问题的方法是COMMIT
语句。删除后,尝试使用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;
/