Как правильно вставить в таблицу, используя таблицу рекордов и все в pl/sql

Я хочу вставить записи в MY_TABLE с помощью forall, Но нет. записей, которые вставляются в данные, меняется с каждым тестом! Я думаю, что это как-то связано со счетчиком циклов, но я не могу понять. Вот фрагмент кода.

DECLARE
  TYPE l_rec_type IS RECORD (
        datakey SOURCE_TABLE.datakey%TYPE,
        sourcekey SOURCE_TABLE.sourcekey%TYPE,
        DESCRIPTION SOURCE_TABLE.DESCRIPTION%TYPE,
        dimension_name SOURCE_TABLE.dimension_name%TYPE ,
        data_type   SOURCE_TABLE.data_type%TYPE

   );


  TYPE l_table_type IS TABLE OF l_rec_typeINDEX BY PLS_INTEGER;
  l_table l_table_type;
  l_cntr NUMBER;
BEGIN
  FOR rec_dimname IN (SELECT dimension_name FROM dimension_table) LOOP
    l_cntr1 := 1
    FOR rec_source IN (SELECT * FROM source_table WHERE data_type IS NOT NULL) LOOP
      l_table(l_ctr1).datakey := rec_source.datakey;
      l_table(l_ctr1).sourcekey := rec_source.sourcekey;
      l_table(l_ctr1).DESCRIPTION := rec_source.DESCRIPTION;
      l_table(l_ctr1).dimension_name := rec_source.dimension_name;
      l_table(l_ctr1).data_type := rec_source.data_type;
      l_cntr1 := l_cntr1+1;
    END LOOP
    FORALL j IN l_table.FIRST..l_table.LAST
      INSERT INTO my_table VALUES(l_table(j).datakey,
                                  l_table(j).sourcekey,
                                  l_table(j).DESCRIPTION,
                                  l_table(j).dimension_name,
                                  l_table(j).data_type,
                                  1,
                                  SYSDATE,
                                  login_id                            
                                 );

  END LOOP;
END;

Что я делаю неправильно? Обычное использование цикла for - это вставка 5000 записей. Другая проблема, с которой я сталкиваюсь, заключается в том, как обрабатывать WHEN DUP_VAL_ON_INDEX и WHEN OTHERS исключение, используя forall. В обычном для петли легко. Но я должен использовать FORALL для быстрых вставок. Пожалуйста помоги!

3 ответа

Решение

Глядя на ваш код, я вижу, что вы не удаляете данные, хранящиеся в таблице pl/ внутри вашего цикла, и у вас нет order by на ваш запрос. Так что если на первой итерации будет больше данных, то на второй вы получите дублирующиеся данные.

Итак, после инициализации вашего l_cntr1 вар (l_cntr1 := 1) вы должны очистить свой pl/table:

l_table.delete;

Надеюсь, это поможет.

Вот фиксированный код. Плюс СОХРАНИТЬ ИСКЛЮЧЕНИЯ действительно спасли мой день! Вот как я реализовал решение. Спасибо всем за ваше драгоценное время и предложения.

DECLARE
      TYPE l_rec_type IS RECORD (
            datakey SOURCE_TABLE.datakey%TYPE,
            sourcekey SOURCE_TABLE.sourcekey%TYPE,
            DESCRIPTION SOURCE_TABLE.DESCRIPTION%TYPE,
            dimension_name SOURCE_TABLE.dimension_name%TYPE ,
            data_type   SOURCE_TABLE.data_type%TYPE

       );


      TYPE l_table_type IS TABLE OF l_rec_typeINDEX BY PLS_INTEGER;
      l_table l_table_type;
      l_cntr NUMBER;
      ex_dml_errors EXCEPTION;
      PRAGMA EXCEPTION_INIT(ex_dml_errors, -24381);
      login_id NUMBER := -1;
      errm VARCHAR2(512);
      err_indx NUMBER
    BEGIN
      FOR rec_dimname IN (SELECT dimension_name FROM dimension_table) LOOP
        l_cntr1 := 1;
        l_table.DELETE; -- Added
        FOR rec_source IN (SELECT * FROM source_table WHERE data_type IS NOT NULL) LOOP
          l_table(l_ctr1).datakey := rec_source.datakey;
          l_table(l_ctr1).sourcekey := rec_source.sourcekey;
          l_table(l_ctr1).DESCRIPTION := rec_source.DESCRIPTION;
          l_table(l_ctr1).dimension_name := rec_source.dimension_name;
          l_table(l_ctr1).data_type := rec_source.data_type;
          l_cntr1 := l_cntr1+1;
        END LOOP
        FORALL j IN l_table.FIRST..l_table.LAST SAVE EXCEPTIONS
          INSERT INTO my_table VALUES(l_table(j).datakey,
                                      l_table(j).sourcekey,
                                      l_table(j).DESCRIPTION,
                                      l_table(j).dimension_name,
                                      l_table(j).data_type,
                                      1,
                                      SYSDATE,
                                      login_id                            
                                     );

          END LOOP;
      END LOOP;
      EXCEPTION
        WHEN ex_dml_errors THEN
          l_error_count := SQL%BULK_EXCEPTIONS.count;
          DBMS_OUTPUT.put_line('Number of failures: ' || l_error_count);
          errm := SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE);
          err_indx := SQL%BULK_EXCEPTIONS(i).error_index
          FOR i IN 1 .. l_error_count LOOP
            DBMS_OUTPUT.put_line('Error: ' || i || 
              ' Array Index: ' || SQL%BULK_EXCEPTIONS(i).error_index ||
              ' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
              IF errm LIKE '%unique%constraint%violated' THEN -- Insert into my_multiple_entries_tbl on duplicate value on index DATAKEY
               INSERT INTO my_multiple_entries_tbl(my_multiple_entries_tbl_seq.NEXTVAL,
                                                   l_table(err_indx).datakey,
                                                   l_table(err_indx).sourcekey,
                                                   l_table(err_indx).data_type, 
                                                   SYSDATE,
                                                   login_id   );

             ELSE -- Insert into my_other_errors_tbl on other errors
               INSERT INTO my_other_errors_tbl  (  my_other_errors_tbl_seq.NEXTVAL,
                                                   l_table(err_indx).datakey,
                                                   l_table(err_indx).sourcekey,
                                                   l_table(err_indx).data_type, 
                                                   SYSDATE,
                                                   login_id   );
             END IF; 
    END;

Вы, кажется, вставляете одну и ту же вещь несколько раз - вы просто просматриваете count из dimension_table, что означает, что это может быть упрощено до следующего, что будет быстрее. Внизу находится forall версия.

Вы не можете использовать exception when dup_val_on_index с любой версией вы должны делать это построчно. Судя только по тому, что вы опубликовали, я подозреваю, что вы действительно можете достичь того, что вы пытаетесь сделать в одном запросе, и полностью сохранить всю эту проблему (включая работу с дублирующимися значениями).

declare

   i integer;

begin

   select count(*)
     into i
     from dimension_table;

   for j in 1 .. i loop

       insert into my_table (datakey, sourcekey, description
                            , dimension_name, someother_column
                            , some_date_column, login_id 
        select datakey, sourcekey, description, dimension_name
             , data_type, 1, sysdate, login_id -- previously missing
          from source_table 
         where data_type is not null;

   end loop;
   commit;

end;
/

Если, однако, вы действительно хотите использовать forall Вы можете сделать что-то вроде этого:

declare

   cursor c_src is
    select datakey, sourcekey, description, dimension_name
         , data_type, 1, sysdate, login_id -- previously missing
      from source_table 
     where data_type is not null;

   type t__src is table of c_src%rowtype index by binary_integer;
   t_src t__src;

   i integer;

begin

   select count(*)
     into i
     from dimension_table;

   for j in 1 .. i loop

      open c_src;
      loop

         fetch c_src bulk collect into t_src;

         forall k in t_src.first .. t_src.last
          insert into my_table (datakey, sourcekey, description
                               , dimension_name, someother_column
                               , some_date_column, login_id 
          values t_src;

      end loop;
      close c_src;

   end loop;
   commit;

end;
/
Другие вопросы по тегам