如何使用pl / sql中的记录表和forall正确插入表中

时间:2012-03-05 19:34:34

标签: collections plsql insert bulk

我想使用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条记录。我面临的另一个问题是如何使用forall处理WHEN DUP_VAL_ON_INDEX和WHEN OTHERS异常。在nornal for循环中它很容易。但我必须使用FORALL进行快速插入。请帮忙!

3 个答案:

答案 0 :(得分:1)

查看您的代码,我可以看到您没有删除存储在循环内pl / table中的数据,并且您的查询没有order by。因此,如果第一次迭代有更多数据,那么第二次迭代将有重复数据。

因此,在初始化l_cntr1 var(l_cntr1 := 1)后,您必须清除pl / table:

l_table.delete;

希望有所帮助。

答案 1 :(得分:1)

这是固定代码。加SAVE EXCEPTIONS真的救了我的一天!以下是我实施解决方案的方法。谢谢大家宝贵的时间和建议。

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;

答案 2 :(得分:0)

您似乎多次插入完全相同的内容 - 您只是循环遍历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;
/