FORALL应该放在for循环之外吗?

时间:2017-07-11 14:14:30

标签: sql oracle plsql oracle11g

我是PL / SQL的新手 我决定使用以下SQL将数千条记录插入表中。但是,将FORALL语句置于for循环外是否正确?
将FORALL语句移到循环块中更好吗?谢谢。

DECLARE

   CURSOR books_cur
   IS
    SELECT book_id, book_type
    FROM books
    WHERE book_category = 'PROGRAMMING';

   TYPE book_ids_t IS TABLE OF 
    books.book_id%TYPE;

   l_book_ids   book_ids_t := book_ids_t();

BEGIN
   FOR i IN books_cur LOOP
    IF(i.book_type = 'PLSQL') THEN
        l_book_ids.EXTENDS;
        l_book_ids(l_book_ids.LAST) := i.book_id;
    END IF;
   END LOOP;

   FORALL i IN l_book_ids.FIRST..l_book_ids.LAST
    INSERT INTO table_a (book_id) VALUES l_book_ids(i);
END;

3 个答案:

答案 0 :(得分:0)

  

“在FOR循环块中移动FORALL语句是否更好”

没有。 FORALL是一个集合操作。您需要在每个工作单元执行一次,而不是每行执行一次。

  

“将数千条记录插入表格”

请记住,馆藏是在会话记忆中维护的。这意味着当您处理大量记录时,您需要更加注意内存管理。

所以你可能想分批工作,这样的事情:

BEGIN
   FOR i IN books_cur LOOP
        IF(i.book_type = 'PLSQL') THEN
            l_book_ids.EXTENDS;
            l_book_ids(l_book_ids.LAST) := i.book_id;
        END IF;
        if l_book_ids.count() = 1000 -- say
        then 
          FORALL i IN l_book_ids.FIRST..l_book_ids.LAST
              INSERT INTO table_a (book_id) VALUES l_book_ids(i);
          l_book_ids.delete();
        end if; 
     END LOOP;
     FORALL i IN l_book_ids.FIRST..l_book_ids.LAST
        INSERT INTO table_a (book_id) VALUES l_book_ids(i);    
END;

此版本的代码以1000个批次的形式插入记录,并附加一个FORALL语句来捕获最后一批可能少于1000条记录的批次。

但是,实现示例的最有效方法仍然是

INSERT INTO table_a (book_id) 
SELECT book_id
FROM books
WHERE book_category = 'PROGRAMMING'
and  book_type = 'PLSQL';

答案 1 :(得分:0)

不,你的FORALL在正确的位置。当然,你的示例程序根本不需要这个,它可以写成:

BEGIN
INSERT INTO table_a (book_id)
SELECT book_id
    FROM books
    WHERE book_category = 'PROGRAMMING'
      AND book_type = 'PLSQL';
END;

但我意识到你对学习FORALL概念感兴趣,而不是编写最简单的代码!

答案 2 :(得分:0)

在您的示例中,FORALL需要集合l_book_ids作为输入。 在FOR循环中,集合尚未完全创建,因此您不能在其上使用FORALL。 FORALL是一个声明,正如APC所提到的,你无法将其分解为多个步骤 - 事实上这是它的优点 - 它可以快速完成工作。