问题
I would like to know is there any way to receive information in PL/SQL how many rows have been updated and how many rows have been inserted while my PL/SQL script using MERGE DML statement.
Let's use Oracle example of merge described here: MERGE example
This functionality is used in my function but also I'd like to log information how many rows has beed updated and how many rows have been inserted.
回答1:
There is a not a built-in way to get separate insert and update counts, no. SQL%ROWCOUNT
would tell you the number of rows merged, as you probably already know, but there is no equivalent to get separate values for the inserts and updates.
This article by Adrian Billington shows a way to get the information by including a function call in the merge, which might add a little overhead.
There's a similar, and perhaps simpler, trick from MichaelS on the Oracle forums, which I can't take any credit for at all either, of course. I'm tempted to reproduce it here but I'm not sure if that's allowed, but essentially it's using sys_context
to maintain a count, in much the same way that Adrian's solution did with a package variable. I'd use that one, as it's cleaner and I think it's easier to follow and maintain.
Still perilously close to a link-only answer but I don't want to plagiarise others' work either...
回答2:
Workarounds pointed by @AlexPoole works, but for me it's strange why don't count updates, inserts and even possible deletes by more natural way with triggers.
Suppose we have simple test table:
create table test_table (id number, col number)
Define simple package for counters
create or replace package pkg_test_table_counter as
procedure reset_counter;
procedure count_insert;
procedure count_update;
procedure count_delete;
function get_insert_count return number;
function get_update_count return number;
function get_delete_count return number;
end;
... and package body:
create or replace package body pkg_test_table_counter as
vUpdateCount number := 0;
vInsertCount number := 0;
vDeleteCount number := 0;
procedure reset_counter is
begin
vUpdateCount := 0;
vInsertCount := 0;
vDeleteCount := 0;
end;
procedure count_insert is
begin
vInsertCount := vInsertCount + 1;
end;
procedure count_update is
begin
vUpdateCount := vUpdateCount + 1;
end;
procedure count_delete is
begin
vDeleteCount := vDeleteCount + 1;
end;
function get_insert_count return number is
begin
return vInsertCount;
end;
function get_update_count return number is
begin
return vUpdateCount;
end;
function get_delete_count return number is
begin
return vDeleteCount;
end;
end;
To count number of rows during execution of single DML statement we need to reset it in before statement trigger
create or replace trigger trg_test_table_counter_reset
before insert or update or delete on test_table
begin
pkg_test_table_counter.reset_counter;
end;
... and increment appropriate counter in trigger for each row:
create or replace trigger trg_test_table_counter_count
before insert or update or delete on test_table
for each row
begin
if inserting then
pkg_test_table_counter.count_insert;
end if;
if updating then
pkg_test_table_counter.count_update;
end if;
if deleting then
pkg_test_table_counter.count_delete;
end if;
end;
So, after executing MERGE
statement without additional tricks inside DML query text it's always possible to get exact number of affected rows:
select
pkg_test_table_counter.get_insert_count insert_count,
(
pkg_test_table_counter.get_update_count
-
pkg_test_table_counter.get_delete_count
) update_count,
pkg_test_table_counter.get_delete_count delete_count
from dual
Note that delete operations also counted as updates for MERGE
, but to keep package useful for another operations there are two separate counters.
SQLFiddle test
来源:https://stackoverflow.com/questions/19156418/oracle-11g-in-pl-sql-is-there-any-way-to-get-info-about-inserted-and-updated-ro