• Bulk SQL Operations


           PL/SQL中的批量操作,允许一次操作和处理多行数据,而不是一次处理一行数据。批量操作包括批量的读取数据,批量的绑定处理处理数据:( bulk fetching and bulk binding)

          Bulk fetching refers to the ability to retrieve a set of rows from the database into PL/SQL structures with a single call, rather than making a call to the database for each row to be retrieved.

          Bulk binding lets you perform the converse: to take those sets of rows stored in
    PL/SQL structures and save them to the database in an efficient manner.
       

    -------------------------------------------------------------------------------------------------

         Getting Started with BULK Fetch

    在PL/SQL中,有三种方法获取行记录:

    1、Implicit Cursor

        SELECT INTO

        (当没有查询到记录,或者查询到的记录多于一行会抛出异常--NO_DATA_FOUND和TO_MANY_ROWS)

    1 DECLARE
    2   l_Descr Hardware.Descr%TYPE;
    3 BEGIN
    4   SELECT Descr
    5     INTO l_Descr
    6     FROM Hardware
    7    WHERE Aisle = 1
    8      AND Item = 1;
    9 END;

    2. Explicit Fetch Calls(手动i打开游标,进行游标的关闭和读取数据)

     1 DECLARE
     2   CURSOR c_Tool_List IS
     3     SELECT Descr
     4       FROM Hardware
     5      WHERE Aisle = 1
     6        AND Item BETWEEN 1 AND 500;
     7   l_Descr Hardware.Descr%TYPE;
     8 BEGIN
     9   OPEN c_Tool_List;
    10   LOOP
    11     FETCH c_Tool_List
    12       INTO l_Descr;
    13     EXIT WHEN c_Tool_List%NOTFOUND;
    14   END LOOP;
    15   CLOSE c_Tool_List;
    16 END;

    3、Implicit Fetch Calls(FOR LOOP循环,游标FOR循环--推荐使用,因为不要进行游标的关闭等)

    1 BEGIN
    2   FOR i IN (SELECT Descr
    3               FROM Hardware
    4              WHERE Aisle = 1
    5                AND Item BETWEEN 1 AND 500) LOOP
    6   <processing code for each row>
    7   END LOOP;
    8 END;

     上述三种情况对应的批量读取数据:

    1. Implicit Cursor BULK Mode:SELECT  BULK COLLECT INTO

     1 DECLARE
     2   TYPE t_Descr_List IS TABLE OF Hardware.Descr%TYPE;
     3   l_Descr_List t_Descr_List;
     4 BEGIN
     5   SELECT Descr BULK COLLECT
     6     INTO l_Descr_List
     7     FROM Hardware
     8    WHERE Aisle = 1
     9      AND Item BETWEEN 1 AND 100;
    10 END;

    2. Explicit Fetch Calls BULK Mode:FETCH BULK COLLECT INTO

     1 DECLARE
     2   CURSOR c_Tool_List IS
     3     SELECT Descr
     4       FROM Hardware
     5      WHERE Aisle = 1
     6        AND Item BETWEEN 1 AND 500;
     7   TYPE t_Descr_List IS TABLE OF c_Tool_List%ROWTYPE;
     8   l_Descr_List t_Descr_List;
     9 BEGIN
    10   OPEN c_Tool_List;
    11   FETCH c_Tool_List BULK COLLECT
    12     INTO l_Descr_List;
    13   CLOSE c_Tool_List;
    14 END;

    在这种情况下,假如使用LIMIT参数,限制每次处理的记录条数:

     1 DECLARE
     2   TYPE Numtab IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
     3   CURSOR C1 IS
     4     SELECT Employee_Id FROM Employees WHERE Department_Id = 80;
     5   Empids Numtab;
     6   Rows   PLS_INTEGER := 10;
     7 BEGIN
     8   OPEN C1;
     9   -- Fetch 10 rows or less in each iteration
    10   LOOP
    11     FETCH C1 BULK COLLECT
    12       INTO Empids LIMIT Rows;
    13     EXIT WHEN Empids.Count = 0;
    14     -- EXIT WHEN c1%NOTFOUND; -- incorrect, can omit some data
    15     Dbms_Output.Put_Line('------- Results from Each Bulk Fetch --------');
    16     FOR i IN 1 .. Empids.Count LOOP
    17       Dbms_Output.Put_Line('Employee Id: ' || Empids(i));
    18     END LOOP;
    19   END LOOP;
    20   CLOSE C1;
    21 END;

    使用

    EXIT WHEN c1%NOTFOUND、使用该语句退出集合存在问题,因为他可能会忽略一些记录,
    应该使用
    EXIT WHEN Empids.Count = 0;来进行游标FOR循环的退出。
    但是也可以在自己的业务处理完毕之后,使用
     EXIT WHEN c1%NOTFOUND;来退出集合

    3、Implicit Fetch Calls BULK mode

    1 BEGIN
    2   FOR i IN (SELECT Descr
    3               FROM Hardware
    4              WHERE Aisle = 1
    5                AND Item BETWEEN 1 AND 500) LOOP
    6     NULL;
    7   END LOOP;
    8 END;

    三种形式的集合:

                • Varray
                • Nested table
                • Associative array

       

    -------------------------------------------------------------------------------------------------

         Getting Started with BULK Fetch

    :FORALL的例子

     1 DECLARE
     2   TYPE t_Row_List IS TABLE OF Hardware%ROWTYPE;
     3   l_Row t_Row_List := t_Row_List();
     4 BEGIN
     5   FOR i IN 1 .. 100 LOOP
     6     l_Row.Extend;
     7     l_Row(i).Aisle := 1;
     8     l_Row(i).Item := i;
     9   END LOOP;
    10   FORALL i IN 1 .. 100
    11     INSERT INTO Hardware VALUES l_Row (i);
    12 END;

    批量处理的标准步骤:

       场景1:Elements Do Not Start at 1,序号没有从1开始,但是他还是连续的,可以使用.FIRST和.LAST作为循环的开始和结束:

     1 DECLARE
     2   TYPE t_Num_List IS TABLE OF Hardware.Item%TYPE INDEX BY PLS_INTEGER;
     3   Val t_Num_List;
     4 BEGIN
     5   Val(10) := 10;
     6   Val(11) := 20;
     7   Val(12) := 20;
     8   FORALL i IN Val.First .. Val.Last
     9     INSERT INTO Hardware (Item) VALUES (Val(i));
    10 END;

    场景2:Elements Are Not Contiguous,不联系的情况,可以使用Oracle提供的INDICES OF函数,

     1 DECLARE
     2   TYPE t_Num_List IS TABLE OF Hardware.Item%TYPE INDEX BY PLS_INTEGER;
     3   Val t_Num_List;
     4 BEGIN
     5   Val(10) := 10;
     6   -- val(11) := 20;
     7   Val(12) := 20;
     8   FORALL i IN INDICES OF Val
     9     INSERT INTO Hardware (Item) VALUES (Val(i));
    10 END;

            I recommend adopting a standard of using the INDICES OF clause whenever you want to process an entire collection, and that use of .FIRST, .LAST, and .COUNT should be deprecated in your PL/SQL code. Sadly, the INDICES OF extension can only be used in a FORALL  statement, not in a standard FOR loop.(推荐在你的代码中使用INDICES OF来处理整个集合,FIRST,LAST,COUNT在你的PL/SQL编码不应该在出现,不幸的是,INDICES OF只可以用在FORALL自居中,不能使用在标准的LOOP循环中。)

    VALUES OF使用:

     1 DECLARE
     2   TYPE t_Input_Row IS RECORD(
     3     Item   Hardware.Item%TYPE,
     4     Descr  Hardware.Descr%TYPE,
     5     Status VARCHAR2(3));
     6   TYPE t_Input_List IS TABLE OF t_Input_Row INDEX BY PLS_INTEGER;
     7   Src t_Input_List;
     8   TYPE t_Target_Indices IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER;
     9   Ind_New t_Target_Indices;
    10   Ind_Upd t_Target_Indices;
    11 BEGIN
    12   FOR i IN 1 .. 100 LOOP
    13     Src(i).Item := i;
    14     Src(i).Descr := 'Item ' || i;
    15     Src(i).Status := CASE
    16                        WHEN MOD(i, 5) = 0 THEN
    17                         'NEW'
    18                        ELSE
    19                         'UPD'
    20                      END;
    21   END LOOP;
    22   FOR i IN 1 .. 100 LOOP
    23     IF Src(i).Status = 'NEW' THEN
    24       Ind_New(Ind_New.Count) := i;
    25     ELSE
    26       Ind_Upd(Ind_Upd.Count) := i;
    27     END IF;
    28   END LOOP;
    29   FORALL i IN VALUES OF Ind_New
    30     INSERT INTO Hardware (Aisle, Item) VALUES (1, Src(i).Item);
    31   Dbms_Output.Put_Line(SQL%ROWCOUNT || ' rows inserted');
    32   FORALL i IN VALUES OF Ind_Upd
    33     UPDATE Hardware
    34        SET Descr = Src(i).Descr
    35      WHERE Aisle = 1
    36        AND Item = Src(i).Item;
    37   Dbms_Output.Put_Line(SQL%ROWCOUNT || ' rows updated');
    38 END;

    --具体请参考:

    <<Expert_PL_SQL_Practices_for_Oracle_Developers_and_DBAs>>:

    Chapter 6: Bulk SQL Operations

  • 相关阅读:
    泛型接口(C# 编程指南) From MSDN
    不知道是不是心理作用,我怎么觉得在Fedora下写cnblogs比Windows下快。
    VS.NET 2005真是太好用了!
    写了个打字游戏,可是有问题(C#)
    C#多线程测试
    关于继承的一个小程序
    VS.NET 2008 试用
    基本排序算法及分析(二):冒泡排序
    基本排序算法及分析(三):shell排序
    [导入]一维数组输出杨辉三角形
  • 原文地址:https://www.cnblogs.com/caroline/p/2529163.html
Copyright © 2020-2023  润新知