2012-03-05 90 views
0

我想使用forall将记录插入MY_TABLE。但是没有。的记录dat插入与每次测试运行不断变化!我认为这与循环计数器有关,但我无法弄清楚。这是代码片段。如何在pl/sql中正确使用记录表和记录表插入表

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异常。在正常循环中很容易。但我必须使用FORALL来快速插入。请帮忙!在你的代码

回答

1

寻找我可以看到你不删除存储在您的循环内的PL /表中的数据,你没有order by您查询的。所以如果第一次迭代有更多的数据,那么第二次你将有重复的数据。

所以初始化您l_cntr1 VAR(l_cntr1 := 1)必须明确你的PL /表后:

l_table.delete; 

希望有所帮助。

+0

谢谢...我会尝试这..希望它解决了我的问题.. – Arcs 2012-03-05 20:30:56

+0

是'l_table.delete'工作就像一个魅力..感谢您的帮助 – Arcs 2012-03-06 18:35:47

+0

大!很高兴帮助:) – 2012-03-06 19:26:48

0

你好像多次插入完全相同的东西 - 你只能循环访问的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; 
/
+0

嗨..我同意你的看法。但我需要有两个for循环,因为在我可以插入到我的表之前进入某些验证逻辑。代码片段是代码设计的概述。我不能使用BULK COLLECT,因为我不是直接从光标选择数据。我必须初始化表格类型元素。我刚刚阅读了SAVE EXCEPTIONS。可能是我可以纳入..我没有事先编码的经验。实际上,整个设计都是在正常for循环内插入MY_TABLE。每当在异常期间发生任何异常,它都被处理并且循环计数器递增 – Arcs 2012-03-05 20:36:58

+0

但是现在,正常插入表中需要花费大量时间,8到9个小时。所以我正在尝试为插入合并FORALL。 – Arcs 2012-03-05 20:40:26

+0

@Arcs,你刚刚说过你发布的所有内容都与你的实际问题无关!你可以使用'bulk collect'来处理你正在做的事情,你直接从光标中选择。如果你正在更新你的类型值,你仍然可以使用'bulk collect'!你真正的问题是什么? – Ben 2012-03-05 20:46:23

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; 
+0

你给出了正确的答案,但似乎没有人理解。 – Cyryl1972 2016-04-13 06:18:12