0% found this document useful (0 votes)
353 views

Advanced PLSQL Bulk Collect N Bulk Bind

The document discusses bulk collect and bulk bind in PL/SQL. It explains that bulk collect allows retrieving multiple rows from a database with a single roundtrip, improving performance. It provides examples of using bulk collect with SELECT, FETCH, and RETURNING clauses to populate PL/SQL collections or records. Bulk bind allows passing entire PL/SQL tables to the database in one step using FORALL, improving bulk DML performance.

Uploaded by

smslca
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
353 views

Advanced PLSQL Bulk Collect N Bulk Bind

The document discusses bulk collect and bulk bind in PL/SQL. It explains that bulk collect allows retrieving multiple rows from a database with a single roundtrip, improving performance. It provides examples of using bulk collect with SELECT, FETCH, and RETURNING clauses to populate PL/SQL collections or records. Bulk bind allows passing entire PL/SQL tables to the database in one step using FORALL, improving bulk DML performance.

Uploaded by

smslca
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

Advanced PLSQL Bulk collect n bulk bind

BULK COLLECT  This is used for array fetches  With this you can retrieve multiple rows of data with a single roundtrip.  This reduces the number of context switches between the pl/sql and sql engines.  Reduces the overhead of retrieving data.  You can use bulk collect in both dynamic and static sql.  You can use bulk collect in select, fetch into and returning into clauses.  SQL engine automatically initializes and extends the collections you reference in the bulk collect clause.  Bulk collect operation empties the collection referenced in the into clause before executing the query.  You can use the limit clause of bulk collect to restrict the no of rows retrieved.  You can fetch into multible collections with one column each.  Using the returning clause we can return data to the another collection.
BULK COLLECT IN FETCH

Ex:
DECLARE

Type t is table of dept%rowtype; nt t; Cursor c is select *from dept;


BEGIN

Open c; Fetch c bulk collect into nt; Close c; For i in nt.first..nt.last loop dbms_output.put_line('Dname = ' || nt(i).dname || ' Loc = ' || nt(i).loc); end loop;
END;

Output: Dname Dname Dname Dname Ex:


DECLARE

= = = =

Loc = NEW YORK RESEARCH Loc = DALLAS SALES Loc = CHICAGO OPERATIONS Loc = BOSTON
ACCOUNTING

BULK COLLECT IN SELECT

Type t is table of dept%rowtype; Nt t;


BEGIN

Select * bulk collect into nt from dept; for i in nt.first..nt.last loop dbms_output.put_line('Dname = ' || nt(i).dname || ' Loc = ' || nt(i).loc); end loop;
END;

Output: Dname Dname Dname Dname Ex:

= = = =

Loc = NEW YORK Loc = DALLAS SALES Loc = CHICAGO OPERATIONS Loc = BOSTON
ACCOUNTING RESEARCH

LIMIT IN BULK COLLECT

DECLARE

Type t is table of dept%rowtype; nt t; Cursor c is select *from dept;


BEGIN

Open c; Fetch c bulk collect into nt; Close c; For i in nt.first..nt.last loop dbms_output.put_line('Dname = ' || nt(i).dname || ' Loc = ' || nt(i).loc); end loop;
END;

Output: Dname = Dname = Ex1:


DECLARE

ACCOUNTING RESEARCH

Loc = NEW YORK Loc = DALLAS

MULTIPLE FETCHES IN INTO CLAUSE

Type t is table of dept.dname%type; nt t; Type t1 is table of dept.loc%type; nt1 t; Cursor c is select dname,loc from dept;
BEGIN

Open c; Fetch c bulk collect into nt,nt1; Close c; For i in nt.first..nt.last loop dbms_output.put_line('Dname = ' || nt(i)); end loop; For i in nt1.first..nt1.last loop dbms_output.put_line('Loc = ' || nt1(i)); end loop;
END;

Output: Dname = ACCOUNTING Dname = RESEARCH Dname = SALES Dname = OPERATIONS Loc = NEW YORK Loc = DALLAS

Loc = Loc = Ex2:

CHICAGO BOSTON

DECLARE

type t is table of dept.dname%type; type t1 is table of dept.loc%type; nt t; nt1 t1;


BEGIN

Select dname,loc bulk collect into nt,nt1 from dept; for i in nt.first..nt.last loop dbms_output.put_line('Dname = ' || nt(i)); end loop; for i in nt1.first..nt1.last loop dbms_output.put_line('Loc = ' || nt1(i)); end loop;
END;

Output: Dname = ACCOUNTING Dname = RESEARCH Dname = SALES Dname = OPERATIONS Loc = NEW YORK Loc = DALLAS Loc = CHICAGO Loc = BOSTON
RETURNING CLAUSE IN BULK COLLECT

declare type t is table of number(2); nt t := t(1,2,3,4); type t1 is table of varchar(2); nt1 t1; type t2 is table of student%rowtype; nt2 t2; begin select name bulk collect into nt1 from student; forall v in nt1.first..nt1.last update student set no = nt(v) where name = nt1(v) returning no,name,marks bulk collect into nt2; for v in nt2.first..nt2.last loop dbms_output.put_line('Marks = ' || nt2(v)); end loop; end; POINTS TO REMEMBER  Cursor name can be up to 30 characters in length.  Cursors declared in anonymous blocks or subprograms closes automatically when that block terminates execution.  %bulk_rowcount and %bulk_exceptions can be used only with forall construct.

 Cursor declarations may have expressions with column aliases.  These expressions are called virtual columns or calculated columns. Bulk Binds  Passing the entire pl/sql table to the SQL engine in one step is known as bulk bind.  Bulk binds are done using the forall statement.  If there is an error processing one of the rows in bulk DML operation, only that row is rolled back. Returning clause  This will be used only with DML statements to return data into pl/sql variables.  This will be useful in situations like , when performing insert or update or delete if you want to know the data of the table which has been effected by the DML.  With out going for another SELECT using RETURNING clause we will get the data which will avoid a call to RDBMS kernel. Bulk Collections and Inserts in Oracle 9i & 10g Performance gains with Bulk Binding Array processing with BULK COLLECT and FORALL Error handling. Native Dynamic SQL with Bulk binding. Typical problems. Oracle 10g FORALL improvements. With SELECT or FETCH statements BULK COLLECT INTO In-Bind binding. INSERT or UPDATE Out-Bind binding. RETURNING clause Data may be Bulk Collected/Fetched into : Table.column%TYPE 8i and above Record of arrays 8i and above Table%ROWTYPE 9.0.2.3 and above Cursor%ROWTYPE 9.0.2.3 and above Array of records 9.0.2.3 and above Nested tables 8i and above SELECT statement Table.column%TYPE DECLARE TYPE cust_tab IS TABLE OF customer.customer_account_id%TYPE INDEX BY BINARY_INTEGER; Custs cust_tab; BEGIN SELECT customer_account_id BULK COLLECT INTO custs FROM customer WHERE effective_date BETWEEN TO_DATE(01-Jan-2004,DD-MON-RRRR) AND TRUNC(SYSDATE); END; FETCH statements Table.column%TYPE DECLARE

TYPE CustList IS TABLE OF Customer.Customer_Account_Id%TYPE INDEX BY BINARY_INTEGER; Custs CustList; CURSOR c1 IS SELECT customer_account_id FROM Customer WHERE effective_date BETWEEN TO_DATE(01-JAN-2004, DD-MON-RRRR) AND TRUNC(SYSDATE); BEGIN OPEN c1; FETCH c1 BULK COLLECT INTO Custs; CLOSE c1; END; FETCH statement:Record of Arrays DECLARE TYPE CustRec IS RECORD (R_Customer_Account_id Customer.Customer_Account_id%TYPE, R_Effective_date Customer.Effective_Date%TYPE, R_Expired_date Customer.Expired_Date%TYPE); v_Custrec CustRec; v_Array_Size NUMBER := 100; CURSOR c1 IS SELECT Customer_Account_Id, Effective_Date, Expired_Date FROM Customer; BEGIN OPEN c1; LOOP FETCH c1 BULK COLLECT INTO v_Custrec.R_Customer_account_id,v_Custrec.R_Effective_Date, v_Custrec.R_Expired_Date LIMIT v_Array_Size; END LOOP; CLOSE c1; END; SELECT statement Table%ROWTYPE DECLARE TYPE Cust_tab IS TABLE OF Customers_Active%ROWTYPE; Custs Cust_tab; BEGIN SELECT Customer_Account_Id, Effective_Date, Expired_Date BULK COLLECT INTO Custs FROM Customers_Active WHERE Effective_date BETWEEN TO_DATE(01-JAN-2004 , DD-MON-RRRR) AND TRUNC(SYSDATE); END; FETCH statement CURSOR%ROWTYPE DECLARE CURSOR c1 IS SELECT Customer_Account_Id, Effective_Date,Expired_Date

FROM Customer WHERE Effective_Date BETWEEN TO_DATE(01-Jan-2004, DD-MON-RRRR) ANDTRUNC(SYSDATE); TYPE Cust_tab IS TABLE OF C1%ROWTYPE; Custs Cust_tab; BEGIN OPEN c1; LOOP FETCH c1 BULK COLLECT INTO Custs LIMIT 100; EXIT WHEN c1%NOTFOUND; END LOOP; END ; FETCH statement: Array Of Records DECLARE TYPE CustRec IS RECORD (R_Customer_Account_id Customer.Customer_Account_id%TYPE, R_Effective_Date Customer.Effective_Date%TYPE, R_Expired_Date Customer.Expired_Date%TYPE); TYPE CustRecTab IS TABLE OF CustRec; Cust_Recs CustRecTab; v_Array_Size NUMBER := 100; CURSOR c1 IS SELECT Customer_Account_Id, Effective_Date, Expired_Date FROM Customer; BEGIN OPEN c1; FETCH c1 BULK COLLECT INTO Cust_Recs LIMIT v_Array_Size; CLOSE c1; END; FETCH statement Nested Tables CREATE TYPE Coords AS OBJECT (x NUMBER, y NUMBER); CREATE TABLE grid (num NUMBER, loc Coords); INSERT INTO grid VALUES(10, Coords(1,2)); INSERT INTO grid VALUES(20, Coords(3,4)); DECLARE TYPE CoordsTab IS TABLE OF Coords; pairs CoordsTab; BEGIN SELECT loc BULK COLLECT INTO pairs FROM grid; -- now pairs contains (1,2) and (3,4) END; In-Bind Binding DECLARE CURSOR c1 SELECT Customer_Account_Id, Effective_Date,Expired_Date FROM Customer WHERE Effective_Date BETWEEN TO_DATE(01-Jan-2003, DD-MON-RRRR) And TO_DATE(01-Jan-2004, DD-MON-RRRR); TYPE Cust_tab IS TABLE OF C1%ROWTYPE;

Custs Cust_tab; BEGIN OPEN c1; LOOP FETCH c1 BULK COLLECT INTO Custs LIMIT 100; END LOOP; FORALL i IN 1 .. Custs.COUNT SAVE EXCEPTIONS INSERT into Customer_History VALUES Custs (i); FORALL Error Handling No more FULL rollback in case of an EXCEPTION  SAVE EXCEPTIONS  SQL%BULK_EXCEPTIONS Collection of records  SQL%BULK_EXCEPTIONS(i).ERROR_INDEX stores itireration when exception is raised. SQL%BULK_EXCEPTIONS(i).ERROR_CODE - stores Oracle error code. Typical Problems FORALL limitations  SINGLE DML (INSERT, UPDATE, DELETE) statement is allowed.  No IF condition within FORALL.  For multi table INSERT/UPDATE use WHEN clause instead of IF condition.  No DBMS_OUTPUT or other OUTPUT statements within FORALL. No SELECT .. BULK COLLECT within FORALL statement. Out-Bind binding DECLARE TYPE AcctTab IS TABLE OF Acct_Install.Customer_Account_id%TYPE; Acusts AcctTab; BEGIN DELETE FROM Acct_Install WHERE INSTALL_DATE = TRUNC(TO_DATE(01-jan-1970,DD-MON-RRRR) RETURNING Customer_Account_Id BULK COLLECT INTO Acusts; END; NATIVE Dynamic SQL EXECUTE IMMEDIATE FORALL RETURNING INTO USING COLLECT INTO %BULK_ROWCOUNT - cursor attribute shows total cumulative execution. NATIVE Dynamic SQL DECLARE TYPE CustList IS TABLE OF NUMBER; TYPE NameList IS TABLE OF VARCHAR2(15); Custnos CustList; Custnames NameList; BEGIN Custnos := CustList(1,2,3,4,5); FORALL i IN 1..5

EXECUTE IMMEDIATE 'UPDATE Customer SET Cust_Name = TRIM(Cust_name) WHERE Custno = :1 RETURNING Cust_Name INTO :2' USING Custnos(i) RETURNING BULK COLLECT INTO Custnames; ... END; Oracle 10g FORALL Indices of When binding area contains gaps Values of Subset of element selection in the array Oracle 10g FORALL VALUES OF DECLARE TYPE CUST_IDS IS TABLE OF CUSTOMER.CUSTOMER_ID%TYPE; TYPE PHONE_NOS IS TABLE OF CUSTOMER.PHONE_NBR%TYPE; TYPE EDATES IS TABLE OF CUSTOMER.EFF_DATE%TYPE; TYPE EXPDATES IS TABLE OF CUSTOMER.EXPIRED_DATE%TYPE; TYPE A_INDX IS TABLE OF PLS_INTEGER INDEX BY PLS_INTEGER; EXPIRED_CUSTS A_INDX; ACTIVE_CUSTS A_INDX; CUSTID CUST_ID; PHONES PHONE_NOS; EFFDTS EDATES; EXPDTS EXPDATES; V_I BINARY_INTEGER BEGIN SELECT CUSTOMER_ID, PHONE_NBR, EFF_DATE, EXPIRED_DATE BULK COLLECT INTO CUSTIDS, PHONES, EFFDTS, EXPDTS; FROM CUSTOMER WHERE Effective_Date BETWEEN TO_DATE(01-Jan-2003, DD-MON-RRRR) And TO_DATE(01-Jan-2004, DD-MON-RRRR); END; FOR v_i IN CUSTIDS.FIRST .. CUSTIDS.LAST LOOP IF FN_EXPIRED THEN EXPIRED_CUSTS (V_I) := v_i; ELSE ACTIVE_CUSTS(V_I) := v_i; END IF; END LOOP; BEGIN FORALL V_ I VALUES OF EXPIRED_CUSTS SAVE EXCEPTIONS INSERT INTO CUSTOMER_HISTORY VALUES (CUSTIDS (V_I), PHONES(V_I), EFFDTS(V_I), EXPDTS(V_); FORALL V_ I VALUES OF ACTIVE_CUSTS SAVE EXCEPTIONS

INSERT INTO CUSTOMER_ACTIVE VALUES (CUSTIDS (V_I), PHONES(V_I), EFFDTS(V_I), EXPDTS(V_); COMMIT; END;

You might also like