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

ORACLE PL/SQL:丢失的最后一个块,oracle,plsql,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

请帮助我解决这个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条记录。 错误在哪里? 在我看来,代码似乎是正确的。 非常感谢您考虑我的请求。

如前所述,您不应该依赖
%NOTFOUND
进行
批量收集
全部
。检查提取了多少行:

  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;
循环
取回我的光标
批量收集到S_数组中
限制P_提交步骤;
对于所有我在1。。S_ARRAY.COUNT
插入我的表格\u BIS/*+追加*/
值S_数组(I);
犯罪
当S_ARRAY.COUNT
您的前1000次迭代将得到10000行,因此计数将等于您对所有这些行的限制,并且将继续。下一个将只获得10行,因此它将在所有
之后退出

它仍然应该与循环末尾的
%NOTFOUND
检查一起工作-如果在处理部分批处理之前使用它退出,本文实际上是在讨论这是一个问题-并显示该模式;但在某些情况下,情况似乎并非如此。话虽如此,我无法从您11.2.0.3中的代码中重现该问题


顺便说一句,在循环内提交通常是个坏主意,除非您已使块可重新启动。

您好,对Forall循环进行了一些小修改

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

我想它会对你有用。

试着调试一下。使用dbms_output.put_line(S_array.count)检查最后一行的计数。它将在最后一行之后提交,即使这在10000范围内,提交也将在过程完成后运行。如果它获取零行,则会出错(如果表为空,或具有限制的精确倍数,则可能会这样做)<代码>1..计数
更安全。(或者你可以做一个单独的空检查。嗨@alex poole,如果一个表不包含任何数据,我可以知道v.first和v.last的值是什么吗?)嗨@alex,如果限制值是该表总行数的精确倍数,那么它是有效的,如果光标也获取零行,那么它也是有效的。如果你需要更多解释,我将发布示例抱歉,我混淆了两件事:第一件和最后一件是空的,它不会出错(但也无助于解决问题);您从
for
循环中得到一个错误,而不是
for all
循环。我的错误。对于要处理数百万甚至数十亿行的ETL场景,我使用相同的通用结构。但是由于数据量大,我必须在循环中使用
提交
,因此我对行计数器使用
mod
操作,仅对
com麻省理工学院
每一次x循环迭代。非常感谢亚历克斯·普尔的帮助!