Advanced PLSQL Bulk Collect n Bulk Bind

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 = ACCOUNTING Loc = NEW YORK Dname = RESEARCH Loc = DALLAS Dname = SALES Loc = CHICAGO Dname = OPERATIONS Loc = BOSTON BULK COLLECT IN SELECT Ex: DECLARE 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

Transcript of Advanced PLSQL Bulk Collect n Bulk Bind

Page 1: Advanced PLSQL Bulk Collect n Bulk Bind

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 loopdbms_output.put_line('Dname = ' || nt(i).dname || ' Loc = ' || nt(i).loc);end loop;

END;

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

BULK COLLECT IN SELECT

Ex:

DECLARE

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

BEGIN

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

END;

Page 2: Advanced PLSQL Bulk Collect n Bulk Bind

Output:Dname = ACCOUNTING Loc = NEW YORK

Dname = RESEARCH Loc = DALLAS Dname = SALES Loc = CHICAGO Dname = OPERATIONS Loc = BOSTON

LIMIT IN BULK COLLECT

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 loopdbms_output.put_line('Dname = ' || nt(i).dname || ' Loc = ' || nt(i).loc);end loop;

END;

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

MULTIPLE FETCHES IN INTO CLAUSE

Ex1:

DECLARE

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 loopdbms_output.put_line('Dname = ' || nt(i));end loop;For i in nt1.first..nt1.last loopdbms_output.put_line('Loc = ' || nt1(i));end loop;

END;

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

Loc = DALLAS

Page 3: Advanced PLSQL Bulk Collect n Bulk Bind

Loc = CHICAGO Loc = BOSTON Ex2:

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 loopdbms_output.put_line('Dname = ' || nt(i));end loop;for i in nt1.first..nt1.last loopdbms_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

declaretype 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;beginselect name bulk collect into nt1 from student;forall v in nt1.first..nt1.lastupdate student set no = nt(v) where name = nt1(v) returning no,name,marks bulk collect into nt2;for v in nt2.first..nt2.last loopdbms_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.

Page 4: Advanced PLSQL Bulk Collect n Bulk Bind

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 & 10gPerformance gains with Bulk BindingArray 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 INTOIn-Bind binding. INSERT or UPDATEOut-Bind binding. RETURNING clauseData may be Bulk Collected/Fetched into :Table.column%TYPE – 8i and aboveRecord of arrays – 8i and aboveTable%ROWTYPE – 9.0.2.3 and aboveCursor%ROWTYPE – 9.0.2.3 and aboveArray of records – 9.0.2.3 and aboveNested tables – 8i and aboveSELECT statement Table.column%TYPEDECLARETYPE cust_tab IS TABLE OF customer.customer_account_id%TYPE INDEX BY BINARY_INTEGER;Custs cust_tab;BEGINSELECT customer_account_id BULK COLLECT INTO custs FROM customerWHERE effective_date BETWEEN TO_DATE(‘01-Jan-2004’,’DD-MON-RRRR’) AND TRUNC(SYSDATE); END;FETCH statements Table.column%TYPEDECLARE

Page 5: Advanced PLSQL Bulk Collect n Bulk Bind

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 DECLARETYPE 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;BEGINOPEN c1;LOOPFETCH 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%ROWTYPEDECLARETYPE Cust_tab IS TABLE OF Customers_Active%ROWTYPE;Custs Cust_tab;BEGINSELECT 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%ROWTYPEDECLARECURSOR c1 ISSELECT Customer_Account_Id, Effective_Date,Expired_Date

Page 6: Advanced PLSQL Bulk Collect n Bulk Bind

FROM CustomerWHERE Effective_Date BETWEEN TO_DATE(’01-Jan-2004’, ‘DD-MON-RRRR’) ANDTRUNC(SYSDATE);TYPE Cust_tab IS TABLE OF C1%ROWTYPE;Custs Cust_tab;BEGINOPEN c1;LOOPFETCH c1 BULK COLLECT INTO Custs LIMIT 100;EXIT WHEN c1%NOTFOUND;END LOOP;END ;FETCH statement: Array Of RecordsDECLARETYPE 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;BEGINOPEN c1;FETCH c1 BULK COLLECT INTO Cust_Recs LIMIT v_Array_Size;CLOSE c1; END; FETCH statement Nested TablesCREATE 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 BindingDECLARECURSOR c1SELECT Customer_Account_Id, Effective_Date,Expired_Date FROM CustomerWHERE 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;

Page 7: Advanced PLSQL Bulk Collect n Bulk Bind

Custs Cust_tab;BEGINOPEN c1;LOOPFETCH c1 BULK COLLECT INTO Custs LIMIT 100;END LOOP;FORALL i IN 1 .. Custs.COUNT SAVE EXCEPTIONSINSERT into Customer_History VALUES Custs (i);FORALL Error HandlingNo 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 bindingDECLARETYPE 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 SQLEXECUTE IMMEDIATEFORALLRETURNING INTOUSING COLLECT INTO %BULK_ROWCOUNT - cursor attribute shows total cumulative execution. NATIVE Dynamic SQLDECLARE 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

Page 8: Advanced PLSQL Bulk Collect n Bulk Bind

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 FORALLIndices of – When binding area contains gaps Values of – Subset of element selection in the arrayOracle 10g FORALL VALUES OFDECLARETYPE 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_INTEGERINDEX BY PLS_INTEGER;EXPIRED_CUSTS A_INDX;ACTIVE_CUSTS A_INDX;CUSTID CUST_ID;PHONES PHONE_NOS;EFFDTS EDATES;EXPDTS EXPDATES;V_I BINARY_INTEGERBEGINSELECT CUSTOMER_ID, PHONE_NBR, EFF_DATE, EXPIRED_DATEBULK COLLECT INTO CUSTIDS, PHONES, EFFDTS, EXPDTS; FROM CUSTOMERWHERE 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.LASTLOOPIF FN_EXPIRED THEN EXPIRED_CUSTS (V_I) := v_i;ELSEACTIVE_CUSTS(V_I) := v_i;END IF;END LOOP;BEGINFORALL V_ I VALUES OF EXPIRED_CUSTSSAVE EXCEPTIONSINSERT INTO CUSTOMER_HISTORY VALUES (CUSTIDS (V_I), PHONES(V_I), EFFDTS(V_I), EXPDTS(V_);FORALL V_ I VALUES OF ACTIVE_CUSTSSAVE EXCEPTIONS

Page 9: Advanced PLSQL Bulk Collect n Bulk Bind

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