Как правильно вставить в таблицу, используя таблицу рекордов и все в pl / sql - PullRequest
0 голосов
/ 05 марта 2012

Я хочу вставить записи в 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;

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

Ответы [ 3 ]

1 голос
/ 06 марта 2012

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

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;
1 голос
/ 05 марта 2012

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

Поэтому после инициализации l_cntr1 var (l_cntr1 := 1) вы должны очистить таблицу pl /:

l_table.delete;

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

0 голосов
/ 06 марта 2012

Похоже, вы вставляете одну и ту же вещь несколько раз - вы просто зацикливаетесь на 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;
/
...