Количество ОБНОВЛЕННЫХ и ВСТАВЛЕННЫХ строк из той же процедуры в PL / SQL - PullRequest
1 голос
/ 27 мая 2020

У меня есть процедура, которая выполняет INSERT INTO, а затем UPDATE некоторых полей (как в одной процедуре), я использую этот ответ от @Clive Количество строк, затронутых ОБНОВЛЕНИЕМ в 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;

ВОПРОС ИЗМЕНЕНО, ЧТОБЫ ПОКАЗАТЬ НАСТОЯЩИЙ ПРИМЕР:

Я создал таблицу, которая берет данные из «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;

Итак, мой первый вывод вставки был:

вставлено => 2821, обновлено => 2821

Итак, я выбрал данные для ча nged, и он был обновлен, я сделал следующий выбор, чтобы выбрать, какие данные следует обновить, чтобы снова ввести вывод СУБД:

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

Data origin

Я прокомментировал в столбце, как показано на изображении, чтобы внести обновление:

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

Я снова запустил процедуру, и результат был:

вставлено => 0 , updated => 2821

Результат для этого обновления:

Result

Разве вы не принесли только 1 обновление данные на выходе, как только 1 обновлено? И не все строки?

например: вставлено => 0, обновлено => 1

Итак, мой вопрос остается, я его задаю правильно? Можно ли получить такой результат такой же процедурой? Это неправильное обновление (несмотря на обновление данных)?

Ответы [ 3 ]

0 голосов
/ 27 мая 2020

Вы не получаете вставленные и обновленные строки. SQL% rowcount содержит ТОЛЬКО количество строк из последнего оператора select или DML. Поскольку вы устанавливаете свою переменную только после обновления, вы получаете только количество обновлений. Если вам нужны оба варианта, вам потребуется отдельная переменная для каждого. Подсказка: нет необходимости делать коммит после каждого DML, на самом деле это часто считается очень плохой практикой. Вам нужно как можно больше изучить транзакции. Основная идея c состоит в том, что все операции завершаются успешно или ни одна из них не завершается успешно. Найдите ATOMI C и 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;
0 голосов
/ 28 мая 2020

Я бы использовал ORA_SCN, как предлагают другие ответы, если вам интересно какие строки были вставлены или обновлены. Но вы хотите знать только их количество, поэтому я бы оставил подсчет на Oracle (может потребоваться много времени для большего количества строк).

Пожалуйста, посмотрите на представление словаря данных USER_TAB_MODIFICATIONS (или ALL_TAB_MODIFICATIONS, если таблица находится в другой схеме, чем процедура.

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

Сбор статистики таблицы сбросит Представление модификаций:

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. Возможно, вам придется предоставить некоторые специальные привилегии схеме, содержащей процедуру. Добавьте комментарий с моим именем, если у вас возникнут проблемы с этим.

0 голосов
/ 27 мая 2020

Попробуйте добавить инструкцию i := SQL%rowcount; после каждого DML:

  1. после INSERT, чтобы было количество вставленных строк
  2. после UPDATE, чтобы количество обновленных строк было
...