ChatGPT解决这个技术问题 Extra ChatGPT

Number of rows affected by an UPDATE in PL/SQL

I have a PL/SQL function (running on Oracle 10g) in which I update some rows. Is there a way to find out how many rows were affected by the UPDATE? When executing the query manually it tells me how many rows were affected, I want to get that number in PL/SQL.


T
Toolkit

You use the sql%rowcount variable.

You need to call it straight after the statement which you need to find the affected row count for.

For example:

set serveroutput ON; 
DECLARE 
    i NUMBER; 
BEGIN 
    UPDATE employees 
    SET    status = 'fired' 
    WHERE  name LIKE '%Bloggs'; 
    i := SQL%rowcount; 
    --note that assignment has to precede COMMIT
    COMMIT; 
    dbms_output.Put_line(i); 
END; 

And assignment has to precede any COMMITs
@Clive I've got a procedure with INSERT INTO..COMMIT and also in the same procedure after the insert, I have UPDATE SET WHERE EXISTS..COMMIT, but my i := SQL%rowcount; is returning all the rows instead of the rows that was updated only. What could be?
C
CLS

For those who want the results from a plain command, the solution could be:

begin
  DBMS_OUTPUT.PUT_LINE(TO_Char(SQL%ROWCOUNT)||' rows affected.');
end;

The basic problem is that SQL%ROWCOUNT is a PL/SQL variable (or function), and cannot be directly accessed from an SQL command. By using a noname PL/SQL block, this can be achieved.

... If anyone has a solution to use it in a SELECT Command, I would be interested.


A
Ali H

alternatively, SQL%ROWCOUNT you can use this within the procedure without any need to declare a variable


SQL%ROWCOUNT is a function, you can't just "use it" - you need to do something with it - whether storing in a variable, or sending it as input to another procedure, or adding it to something else.
I think that Ali H's point is that it's not necessary to assign it to a variable until you have another SQL statement that would affect the row count. That being said, I agree that it should be assigned to a variable to avoid causing a bug later should someone add another SQL statement before it is called. And, this answer from Ali H should be a comment on Clive's answer rather than posted as a separate answer
J
J. Chomel

SQL%ROWCOUNT can also be used without being assigned (at least from Oracle 11g).

As long as no operation (updates, deletes or inserts) has been performed within the current block, SQL%ROWCOUNT is set to null. Then it stays with the number of line affected by the last DML operation:

say we have table CLIENT

create table client (
  val_cli integer
 ,status varchar2(10)
)
/

We would test it this way:

begin
  dbms_output.put_line('Value when entering the block:'||sql%rowcount);

  insert into client 
            select 1, 'void' from dual
  union all select 4, 'void' from dual
  union all select 1, 'void' from dual
  union all select 6, 'void' from dual
  union all select 10, 'void' from dual;  
  dbms_output.put_line('Number of lines affected by previous DML operation:'||sql%rowcount);

  for val in 1..10
    loop
      update client set status = 'updated' where val_cli = val;
      if sql%rowcount = 0 then
        dbms_output.put_line('no client with '||val||' val_cli.');
      elsif sql%rowcount = 1 then
        dbms_output.put_line(sql%rowcount||' client updated for '||val);
      else -- >1
        dbms_output.put_line(sql%rowcount||' clients updated for '||val);
      end if;
  end loop;  
end;

Resulting in:

Value when entering the block:
Number of lines affected by previous DML operation:5
2 clients updated for 1
no client with 2 val_cli.
no client with 3 val_cli.
1 client updated for 4
no client with 5 val_cli.
1 client updated for 6
no client with 7 val_cli.
no client with 8 val_cli.
no client with 9 val_cli.
1 client updated for 10

A
Arun Sundriyal

Please try this one..

create table client (
  val_cli integer
 ,status varchar2(10)
);

---------------------
begin
insert into client
select 1, 'void' from dual
union all
select 4, 'void' from dual
union all
select 1, 'void' from dual
union all
select 6, 'void' from dual
union all
select 10, 'void' from dual;
end;

---------------------
select * from client;

---------------------
declare
  counter integer := 0;
begin
  for val in 1..10
    loop
      update client set status = 'updated' where val_cli = val;
      if sql%rowcount = 0 then
        dbms_output.put_line('no client with '||val||' val_cli.');
      else
        dbms_output.put_line(sql%rowcount||' client updated for '||val);
        counter := counter + sql%rowcount;
      end if;
  end loop;
   dbms_output.put_line('Number of total lines affected update operation: '||counter);
end;

---------------------
select * from client;

--------------------------------------------------------

Result will be like below:

2 client updated for 1 no client with 2 val_cli. no client with 3 val_cli. 1 client updated for 4 no client with 5 val_cli. 1 client updated for 6 no client with 7 val_cli. no client with 8 val_cli. no client with 9 val_cli. 1 client updated for 10 Number of total lines affected update operation: 5


Add comments to your solution, Please be specific.
g
guest

Use the Count(*) analytic function OVER PARTITION BY NULL This will count the total # of rows


After running update statement if you check the count on what you actually updated - This doesn't give any generic solution. For example, if my table T has one column c1 which contains "1" as value for all and now I update all rows for that column to "2", how will partitioning by null help?