首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从未输入FORALL时的FORALL和sql%rowcount

从未输入FORALL时的FORALL和sql%rowcount
EN

Stack Overflow用户
提问于 2019-06-05 15:57:51
回答 2查看 3.2K关注 0票数 2

我很好奇你们是如何处理这个问题的,sql%rowcount不是在一个根本没有输入的FORALL之后设置的。下面是我如何解决这个问题的示例(使用一个变量v_rowcountFORALL所基于的集合的count )。但我觉得有一种更聪明的方法:

代码语言:javascript
复制
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;
/
EN

回答 2

Stack Overflow用户

发布于 2019-06-05 20:25:46

我会像你的例子中那样做,但也有其他选择。我们可以使用对forall更好的sql%bulk_rowcount。下面是Oracle的link文档和一些示例。这是我的测试表:

代码语言:javascript
复制
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_rowcounts:

代码语言:javascript
复制
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;

结果:

代码语言:javascript
复制
sql rowcount: 3
sum of bull_rowcount: 3
sql rowcount: 3          -- "wrong", value from previous DML
sum of bull_rowcount: 0
票数 2
EN

Stack Overflow用户

发布于 2019-06-05 16:30:58

SQL%ROWCOUNT与FORALL一起使用

如下例所示:

代码语言:javascript
复制
-- 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;

代码语言:javascript
复制
-- 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;
/

代码语言:javascript
复制
-- Output after data is updated
SELECT * FROM EMPLOYEES;

因此,根据我的示例,即使我们使用FORALL,它也会在SQL%ROWCOUNT中存储一些受影响的行。-但是,但是,如果我在'DELETE‘语句后删除'COMMIT’,那么我也面临着与您描述的相同的问题。

因此,您的问题的解决方案是COMMIT语句。尝试在delete之后使用commit语句运行代码。

希望,这对你很有用。

已更新

代码语言:javascript
复制
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;
/
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56456344

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档