请帮我解决这个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条记录。 错误在哪里? 在我看来,代码似乎是正确的。 非常感谢你考虑我的要求。
答案 0 :(得分:2)
如上所述[{3}},您不应该依赖%NOTFOUND
bulk collect
和forall
。检查提取的行数:
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);
我认为这对你有用。