PL/SQL 中同一过程更新和插入的行数

Number of rows UPDATED and INSERTED from the same procedure in PL/SQL

我有一个程序执行某些字段的 INSERT INTO 然后 UPDATE(两者都在同一程序中),我正在使用来自@Clive Number of rows affected by an UPDATE in PL/SQL 的答案知道已更新到日志中的数据量,但它给我带来了总行数,而不仅仅是已更新的记录。

这是正确的了解方式吗?

我需要知道从 INSERT STATEMENT 中插入了多少行以及从 UPDATE STATEMENT.

中更新了多少行

我的查询:

CREATE OR REPLACE PROCEDURE OWNER.TABLE_NAME
AS

 -- VARIABLE
 v_qtd_regs  number := 0;  
 v_code      number;
 v_errm      VARCHAR2(500);
 start_time  pls_integer;
 end_time    pls_integer;
 elapse_time number;
 proc_name   varchar2(100);
 i NUMBER;

BEGIN
   proc_name := 'PRDWBI_CGA_D_COLUMNS';
   start_time := dbms_utility.get_time;
   DS_FUNCESP.PRDSBI_GRAVA_LOG( 'I', 'DataWarehouse', proc_name, 'Início Carga' );

   -- INSERT INTO TABLE:
   INSERT INTO OWNER.TABLE_NAME
   (COLUMN_ID, COLUMNS_NAME, COLUMN_NAME2)
   (SELECT 1 AS COLUMN_ID, 'TEST' AS COLUMN_NAME, SYSDATE AS COLUMN_NAME2 FROM DUAL);

   COMMIT;

  -- UPDATE SOME COLUMNS I NEED
   UPDATE OWNER.TABLE_NAME y
   SET (y.COLUMNS_NAME, y.COLUMN_NAME2) = 
               (SELECT 'TEST2' AS COLUMN_NAME, SYSDATE AS COLUMN_NAME2 FROM DUAL x WHERE x.COLUMN_ID = y.COLUMN_ID)
   WHERE EXISTS (SELECT 'TEST2' AS COLUMN_NAME, SYSDATE AS COLUMN_NAME2 FROM DUAL x WHERE x.COLUMN_ID = y.COLUMN_ID);

   -- TO KNOW HOW MANY ROWS WERE UPDATED
   i := SQL%rowcount;     

   COMMIT;  

   --dbms_output.Put_line(i);

   SELECT COUNT(1) INTO v_qtd_regs FROM OWNER.TABLE_NAME where LinData >= TRUNC(SYSDATE);
   end_time := dbms_utility.get_time;
   elapse_time := ((end_time - start_time)/100);
   v_errm := SUBSTR(SQLERRM, 1 , 500);
   DS_FUNCESP.PRDSBI_GRAVA_LOG('T', 'DataWarehouse', proc_name, v_errm, v_qtd_regs, elapse_time );

   COMMIT;

EXCEPTION
   WHEN OTHERS THEN
      v_code := SQLCODE;
      v_errm := SUBSTR(SQLERRM, 1 , 500);
      DS_FUNCESP.PRDSBI_GRAVA_LOG('E', 'Error', proc_name, v_errm);

END;

已编辑问题以显示真实示例:

我创建了一个 table 从 "SYS.DBA_TAB_COLUMNS" 中获取数据只是为了用作示例,如下所示:

  CREATE TABLE "DW_FUNCESP"."D_TEST"
    (
        "ID_COLUMN" NUMBER(10,0) GENERATED BY DEFAULT ON NULL AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1
        START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
        "NM_OWNER"  VARCHAR2(500 CHAR) NOT NULL ENABLE                       ,
        "NM_TABLE"  VARCHAR2(500 CHAR) NOT NULL ENABLE                       ,
        "CD_COLUMN" NUMBER(20,0) NOT NULL ENABLE                             ,
        "NM_COLUMN" VARCHAR2(500 CHAR) NOT NULL ENABLE                       ,
        "DS_COLUMN" VARCHAR2(500 CHAR) NOT NULL ENABLE                       ,
        "LINDATE"   DATE DEFAULT SYSDATE NOT NULL ENABLE                     ,
        "LINORIGIN" VARCHAR2(100 CHAR) NOT NULL ENABLE
    )

然后我创建了一个程序来识别插入和更新的记录,如下所示:

CREATE OR REPLACE PROCEDURE DW_FUNCESP.PRDWBI_CGA_D_TEST
AS

 -- variaveis de suporte as informações que deve gravar
 rows_inserted integer;
 rows_updated  integer;

BEGIN

   -- Insert Into table
   INSERT INTO DW_Funcesp.D_TEST
   (NM_OWNER, NM_TABLE, CD_COLUMN, NM_COLUMN, DS_COLUMN, LINDATE, LINORIGIN)
   (SELECT
      NVL(x.NM_OWNER ,'NOT FOUND')      AS NM_OWNER     ,
      NVL(x.NM_TABLE ,'NOT FOUND')      AS NM_TABLE     ,
      NVL(x.CD_COLUMN ,-1)              AS CD_COLUMN    ,
      NVL(x.NM_COLUMN ,'NOT FOUND')     AS NM_COLUMN    ,
      NVL(x.DS_COLUMN ,x.NM_COLUMN)     AS DS_COLUMN    ,
      SYSDATE                           AS LINDATE      ,
      'SYS.DBA_TAB_COLUMNS'             AS LINORIGIN
    FROM
      (
        SELECT
          d.OWNER       AS NM_OWNER ,
          d.TABLE_NAME  AS NM_TABLE ,
          d.COLUMN_ID   AS CD_COLUMN,
          d.COLUMN_NAME AS NM_COLUMN,
          e.COMMENTS    AS DS_COLUMN
        FROM SYS.DBA_TAB_COLUMNS d
        LEFT JOIN SYS.DBA_COL_COMMENTS e
          ON e.OWNER           = d.OWNER
          AND e.TABLE_NAME  = d.TABLE_NAME
          AND e.COLUMN_NAME = d.COLUMN_NAME
        WHERE d.OWNER = 'DW_FUNCESP'
       ) x
    LEFT JOIN DW_FUNCESP.D_TEST y
      ON  y.NM_OWNER = x.NM_OWNER
      AND y.NM_TABLE = x.NM_TABLE
      AND y.NM_COLUMN = x.NM_COLUMN
    WHERE y.ID_COLUMN IS NULL);

    rows_inserted := sql%rowcount;

  -- Update the table
   UPDATE DW_FUNCESP.D_TEST z
   SET (z.NM_COLUMN, z.DS_COLUMN, z.LINDATE) = 
                  (SELECT
                      NVL(x.NM_COLUMN ,'NOT FOUND')     AS NM_COLUMN    ,
                      NVL(x.DS_COLUMN ,x.NM_COLUMN)     AS DS_COLUMN    ,
                      SYSDATE                           AS LINDATE      
                    FROM
                      (
                        SELECT
                          d.OWNER       AS NM_OWNER ,
                          d.TABLE_NAME  AS NM_TABLE ,
                          d.COLUMN_ID   AS CD_COLUMN,
                          d.COLUMN_NAME AS NM_COLUMN,
                          e.COMMENTS    AS DS_COLUMN
                        FROM SYS.DBA_TAB_COLUMNS d
                        LEFT JOIN SYS.DBA_COL_COMMENTS e
                          ON e.OWNER           = d.OWNER
                          AND e.TABLE_NAME  = d.TABLE_NAME
                          AND e.COLUMN_NAME = d.COLUMN_NAME
                        WHERE d.OWNER = 'DW_FUNCESP'
                       ) x
                    WHERE z.NM_OWNER = x.NM_OWNER
                      AND z.NM_TABLE = x.NM_TABLE
                      AND z.CD_COLUMN = x.CD_COLUMN)
   WHERE EXISTS (SELECT
                      NVL(x.NM_COLUMN ,'NOT FOUND')     AS NM_COLUMN    ,
                      NVL(x.DS_COLUMN ,x.NM_COLUMN)     AS DS_COLUMN    ,
                      SYSDATE                           AS LINDATE      
                    FROM
                      (
                        SELECT
                          d.OWNER       AS NM_OWNER ,
                          d.TABLE_NAME  AS NM_TABLE ,
                          d.COLUMN_ID   AS CD_COLUMN,
                          d.COLUMN_NAME AS NM_COLUMN,
                          e.COMMENTS    AS DS_COLUMN
                        FROM SYS.DBA_TAB_COLUMNS d
                        LEFT JOIN SYS.DBA_COL_COMMENTS e
                          ON e.OWNER           = d.OWNER
                          AND e.TABLE_NAME  = d.TABLE_NAME
                          AND e.COLUMN_NAME = d.COLUMN_NAME
                        WHERE d.OWNER = 'DW_FUNCESP'
                       ) x
                    WHERE z.NM_OWNER = x.NM_OWNER
                      AND z.NM_TABLE = x.NM_TABLE
                      AND z.CD_COLUMN = x.CD_COLUMN);

   rows_updated := sql%rowcount; 

   dbms_output.Put_line('inserted=>' || to_char(rows_inserted) || ', updated=>' || to_char(rows_updated));

   COMMIT;

EXCEPTION
   WHEN OTHERS THEN
      RAISE;

END;

所以我的第一个插入输出是:

inserted=>2821, updated=>2821

所以我选择了一个要更改的数据并更新了,我做了以下select来选择应该更新哪些数据以再次引入DBMS输出:

SELECT * FROM DW_FUNCESP.D_TEST WHERE NM_TABLE = 'D_TEST';

我在如图所示的专栏中发表评论,以引入更新:

COMMENT ON COLUMN DW_FUNCESP.D_TEST.LINORIGIN IS 'The origin of the data';

我再次运行程序,输出是:

inserted=>0, updated=>2821

该更新的结果:

你不应该在输出中只带 1 个更新数据吗,因为只有 1 个更新?不是所有行?

e.g.: inserted=>0, updated=>1

所以我的问题仍然存在,我问的对吗?是否有可能在相同的程序中获得此结果?是不是更新不正确(尽管已经更新了数据)?

尝试在每个 DML 后添加指令 i := SQL%rowcount;

  1. INSERT 后插入的行数
  2. UPDATE 后更新的行数

您没有插入行和更新行。 SQL%rowcount 仅包含最后一个 select 或 DML 语句的行数。由于您仅在更新后才设置变量,因此您只能获得更新次数。如果你想要两者,那么你需要为每个单独的变量。
提示:无需在每个 DML 之后提交,实际上这通常被认为是一种非常糟糕的做法。您需要研究交易。基本思想是所有操作都成功完成或其中 none 成功完成。查找 ATOMIC 和 Atomicity

所以你修改后的程序变成:

create or replace procedure owner.table_name
as

 -- VARIABLE
 v_qtd_regs  number := 0;  
 v_code      number;
 v_errm      varchar2(500);
 start_time  pls_integer;
 end_time    pls_integer;
 elapse_time number;
 proc_name   varchar2(100);
 rows_inserted integer;
 rows_updated  integer;
begin
   proc_name := 'PRDWBI_CGA_D_COLUMNS';
   start_time := dbms_utility.get_time;
   ds_funcesp.prdsbi_grava_log( 'I', 'DataWarehouse', proc_name, 'Início Carga' );


   insert into owner.table_name
   (column_id, columns_name, column_name2)
   (select 1 as column_id, 'TEST' as column_name, sysdate as column_name2 from dual);

   rows_inserted := sql%rowcount;

   update owner.table_name y
   set (y.columns_name, y.column_name2) = 
               (select 'TEST2' as column_name, sysdate as column_name2 from dual x where x.column_id = y.column_id)
   where exists (select 'TEST2' as column_name, sysdate as column_name2 from dual x where x.column_id = y.column_id);

   rows_updated := sql%rowcount;     


   dbms_output.Put_line('inserted=>' || to_char(rows_inserted) || ', updated=>' || tp_char(rows_updated));

   select count(1) into v_qtd_regs from owner.table_name where lindata >= trunc(sysdate);
   end_time := dbms_utility.get_time;
   elapse_time := ((end_time - start_time)/100);
   v_errm := substr(sqlerrm, 1 , 500);
   ds_funcesp.prdsbi_grava_log('T', 'DataWarehouse', proc_name, v_errm, v_qtd_regs, elapse_time );

   commit;

exception
   when others then
      v_code := sqlcode;
      v_errm := substr(sqlerrm, 1 , 500);
      ds_funcesp.prdsbi_grava_log('E', 'Error', proc_name, v_errm);

end;

如果您有兴趣,我会使用 ORA_SCN 作为其他答案的建议 插入或更新了哪些 行。但是您只想知道有多少,所以我会将计数留给 Oracle(对于大量行可能会很耗时)。

请查看数据字典视图 USER_TAB_MODIFICATIONS(或 ALL_TAB_MODIFICATIONS,如果 table 在与过程不同的模式中。

CREATE TABLE d (
  id  NUMBER GENERATED ALWAYS AS IDENTITY,
  dt  DATE DEFAULT SYSDATE,
  foo VARCHAR2(128 BYTE)
);

收集 table 统计数据将重置修改视图:

EXEC DBMS_STATS.GATHER_TABLE_STATS(NULL,'D');

现在在您的 INSERT 之后,修改视图将具有插入的行数:

INSERT INTO d(foo) SELECT object_name FROM all_objects;
67,141 rows inserted.

SELECT inserts, updates, deletes FROM user_tab_modifications WHERE table_name='D';
INSERTS UPDATES DELETES
  67141       0       0

同样,在 UPDATE 之后,更新的行:

UPDATE d SET foo=lower(foo),dt=SYSDATE WHERE mod(id,10)=0; 
6,714 rows updated.

SELECT inserts, updates, deletes FROM user_tab_modifications WHERE table_name='D';
INSERTS UPDATES DELETES
  67141    6714       0

为清楚起见,我使用了 SQL 而不是 PL/SQL。您可能必须向包含该过程的模式授予一些特殊权限。如果您 运行 遇到问题,请用我的名字添加评论。