ORACLE PL / SQL:丢失的最后一块

时间:2015-08-07 08:11:39

标签: oracle plsql

请帮我解决这个ORACLE PL / SQL问题。

我有以下代码:

BEGIN
   DECLARE
      P_COMMIT_STEP   NUMBER := 10000;       -- Commit every 10000 record copied
      V_QUERY         VARCHAR2 (4000) := NULL;
      MY_CURSOR       SYS_REFCURSOR;

      TYPE FETCH_ARRAY IS TABLE OF MY_TABLE_BACKUP%ROWTYPE;

      S_ARRAY         FETCH_ARRAY;
   BEGIN
      V_QUERY := 'SELECT * FROM MY_TABLE_BACKUP';

      OPEN MY_CURSOR FOR V_QUERY;

      LOOP
         FETCH MY_CURSOR
         BULK COLLECT INTO   S_ARRAY
         LIMIT P_COMMIT_STEP;

         FORALL I IN 1 .. S_ARRAY.COUNT
            INSERT INTO MY_TABLE_BIS                               /*+ APPEND */
              VALUES   S_ARRAY (I);

         COMMIT;


         EXIT WHEN MY_CURSOR%NOTFOUND;
      END LOOP;

      CLOSE MY_CURSOR;

      COMMIT;
   END;
END;

由于提交步骤为10000,因此副本适用于10000记录的倍数。 因此,如果原始表具有1000010条记录,则仅复制1000000条记录。 错误在哪里? 在我看来,代码似乎是正确的。 非常感谢你考虑我的要求。

2 个答案:

答案 0 :(得分:2)

如上所述[{3}},您不应该依赖%NOTFOUND bulk collectforall。检查提取的行数:

  LOOP
     FETCH MY_CURSOR
     BULK COLLECT INTO   S_ARRAY
     LIMIT P_COMMIT_STEP;

     FORALL I IN 1 .. S_ARRAY.COUNT
        INSERT INTO MY_TABLE_BIS                               /*+ APPEND */
          VALUES   S_ARRAY (I);

     COMMIT;


     EXIT WHEN S_ARRAY.COUNT < P_COMMIT_STEP;
  END LOOP;

你的前几千个迭代将获得10000行,因此计数将等于所有这些的限制,并且它将继续。下一个将只获得10行,因此它将在forall之后退出。

它应该 仍然可以在循环结束时使用%NOTFOUND检查 - 如果您在处理部分批处理之前使用它退出,那么文章真的在谈论它是一个问题 - 而in this article显示了这种模式;但在某些情况下似乎并非如此。话虽如此,我无法通过11.2.0.3中的代码重现该问题。

顺便提一下,除非你已经重新启动了块,否则在循环内部提交通常是一个坏主意。

答案 1 :(得分:0)

对您的Forall循环进行小修改

FORALL I IN S_ARRAY.first .. S_ARRAY.last
            INSERT INTO MY_TABLE_BIS                               /*+ APPEND */
              VALUES   S_ARRAY (I);

我认为这对你有用。