zoukankan      html  css  js  c++  java
  • BULK COLLECT

        Using the keywords BULK COLLECT with a query is a very efficient way to retrieve the result set. Instead of looping through each row, you store the results in one or more collections, in a single operation. You can use these keywords in the SELECT INTO and FETCH INTO statements, and the RETURNING INTO clause.

    Example 11-10 Retrieving Query Results With BULK COLLECT
     
    DECLARE
      TYPE NameList IS TABLE OF employees.last_name%TYPE;
      TYPE SalList IS TABLE OF employees.salary%TYPE;
      CURSOR c1 IS SELECT last_name, salary FROM employees WHERE salary > 10000;
      names NameList;
      sals  SalList;
      TYPE RecList IS TABLE OF c1%ROWTYPE;
      recs RecList;
      v_limit PLS_INTEGER := 10;
      PROCEDURE print_results IS
      BEGIN
        IF names IS NULL OR names.COUNT = 0 THEN  -- check if collections are empty
           DBMS_OUTPUT.PUT_LINE('No results!');
        ELSE
          DBMS_OUTPUT.PUT_LINE('Results: ');
          FOR i IN names.FIRST .. names.LAST
          LOOP
            DBMS_OUTPUT.PUT_LINE('  Employee ' || names(i) || ': $' || sals(i));
          END LOOP;
        END IF;
      END;
    BEGIN
      DBMS_OUTPUT.PUT_LINE('--- Processing all results at once ---');
      OPEN c1;
      FETCH c1 BULK COLLECT INTO names, sals;
      CLOSE c1;
      print_results();
      DBMS_OUTPUT.PUT_LINE('--- Processing ' || v_limit || ' rows at a time ---');
      OPEN c1;
      LOOP
        FETCH c1 BULK COLLECT INTO names, sals LIMIT v_limit;
        EXIT WHEN names.COUNT = 0;
        print_results();
      END LOOP;
      CLOSE c1;
      DBMS_OUTPUT.PUT_LINE('--- Fetching records rather than columns ---');
      OPEN c1;
      FETCH c1 BULK COLLECT INTO recs;
      FOR i IN recs.FIRST .. recs.LAST
      LOOP
    -- Now all the columns from the result set come from a single record
        DBMS_OUTPUT.PUT_LINE('  Employee ' || recs(i).last_name || ': $'
             || recs(i).salary);
      END LOOP;
    END;
    /

    Example 11-13 shows how you can fetch from a cursor into a collection of records.

    Example 11-13 Bulk-Fetching from a Cursor Into a Collection of Records

    DECLARE
      TYPE DeptRecTab IS TABLE OF departments%ROWTYPE;
      dept_recs DeptRecTab;
      CURSOR c1 IS
        SELECT department_id, department_name, manager_id, location_id 
          FROM departments WHERE department_id > 70;
    BEGIN
      OPEN c1;
      FETCH c1 BULK COLLECT INTO dept_recs;
    END;
    /


    Limiting the Rows for a Bulk FETCH Operation with the LIMIT Clause

    The optional LIMIT clause, allowed only in bulk FETCH statements, limits the number of rows fetched from the database. In Example 11-14, with each iteration of the loop, the FETCH statement fetches ten rows (or less) into index-by table empids. The previous values are overwritten. Note the use of empids.COUNT to determine when to exit the loop.

    Example 11-14 Using LIMIT to Control the Number of Rows In a BULK COLLECT

    DECLARE
       TYPE numtab IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
       CURSOR c1 IS SELECT employee_id FROM employees WHERE department_id = 80;
       empids    numtab;
       rows      PLS_INTEGER := 10;
    BEGIN
      OPEN c1;
      LOOP -- the following statement fetches 10 rows or less in each iteration
        FETCH c1 BULK COLLECT INTO empids LIMIT rows;
        EXIT WHEN empids.COUNT = 0;
    --  EXIT WHEN c1%NOTFOUND; -- incorrect, can omit some data
        DBMS_OUTPUT.PUT_LINE('------- Results from Each Bulk Fetch --------');
        FOR i IN 1..empids.COUNT LOOP
          DBMS_OUTPUT.PUT_LINE( 'Employee Id: ' || empids(i));
        END LOOP;
      END LOOP;
      CLOSE c1;
    END;
    /

    Retrieving DML Results into a Collection with the RETURNING INTO Clause

    You can use the BULK COLLECT clause in the RETURNING INTO clause of an INSERTUPDATE, or DELETE statement:

    Example 11-15 Using BULK COLLECT With the RETURNING INTO Clause

    CREATE TABLE emp_temp AS SELECT * FROM employees;
    DECLARE
       TYPE NumList IS TABLE OF employees.employee_id%TYPE;
       enums NumList;
       TYPE NameList IS TABLE OF employees.last_name%TYPE;
       names NameList;
    BEGIN
       DELETE FROM emp_temp WHERE department_id = 30
          RETURNING employee_id, last_name BULK COLLECT INTO enums, names;
       DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows:');
       FOR i IN enums.FIRST .. enums.LAST
       LOOP
          DBMS_OUTPUT.PUT_LINE('Employee #' || enums(i) || ': ' || names(i));
       END LOOP;
    END;
    /
    Using FORALL and BULK COLLECT Together

    You can combine the BULK COLLECT clause with a FORALL statement. The output collections are built up as the FORALL statement iterates.


    In Example 11-16, the employee_id value of each deleted row is stored in the collection e_ids. The collection depts has 3 elements, so the FORALL statement iterates 3 times. If each DELETE issued by the FORALL statement deletes 5 rows, then the collection e_ids, which stores values from the deleted rows, has 15 elements when the statement completes:

    Example 11-16 Using FORALL With BULK COLLECT

    CREATE TABLE emp_temp AS SELECT * FROM employees;
    DECLARE
       TYPE NumList IS TABLE OF NUMBER;
       depts NumList := NumList(10,20,30);
       TYPE enum_t IS TABLE OF employees.employee_id%TYPE;
       TYPE dept_t IS TABLE OF employees.department_id%TYPE;
       e_ids enum_t;
       d_ids dept_t;
    BEGIN
      FORALL j IN depts.FIRST..depts.LAST
        DELETE FROM emp_temp WHERE department_id = depts(j)
           RETURNING employee_id, department_id BULK COLLECT INTO e_ids, d_ids;
      DBMS_OUTPUT.PUT_LINE('Deleted ' || SQL%ROWCOUNT || ' rows:');
      FOR i IN e_ids.FIRST .. e_ids.LAST
      LOOP
        DBMS_OUTPUT.PUT_LINE('Employee #' || e_ids(i) || ' from dept #' || d_ids(i));
      END LOOP;
    END;
    /
    
    

    The column values returned by each execution are added to the values returned previously. If you use a FOR loop instead of the FORALL statement, the set of returned values is overwritten by each DELETE statement.

    You cannot use the SELECT ... BULK COLLECT statement in a FORALL statement.


    Using Host Arrays with Bulk Binds

    Client-side programs can use anonymous PL/SQL blocks to bulk-bind input and output host arrays. This is the most efficient way to pass collections to and from the database server.

    Host arrays are declared in a host environment such as an OCI or a Pro*C program and must be prefixed with a colon to distinguish them from PL/SQL collections. In the following example, an input host array is used in a DELETE statement. At run time, the anonymous PL/SQL block is sent to the database server for execution.


    DECLARE
      ...
    BEGIN
      -- assume that values were assigned to the host array
      -- and host variables in the host environment
      FORALL i IN :lower..:upper
        DELETE FROM employees WHERE department_id = :depts(i);
      COMMIT;
    END;
    /

  • 相关阅读:
    升级系统引起的
    php curl批处理
    看《黑炮事件》想到的
    查找单链表的倒数第k个值
    python绘制树枝
    暑假第九测
    网络流24题(持续更新)
    P2657 [SCOI2009]windy数
    P3177 [HAOI2015]树上染色
    暑假第六测
  • 原文地址:https://www.cnblogs.com/huangjiandong2012/p/2163487.html
Copyright © 2011-2022 走看看