PL-SQL Collections and Records

download PL-SQL Collections and Records

of 50

Transcript of PL-SQL Collections and Records

  • 7/28/2019 PL-SQL Collections and Records

    1/50

    Skip Headers

    5PL/SQL Collections and Records

    Knowledge is that area of ignorance that we arrange and classify. --Ambrose Bierce

    Many programming techniques use collection types such as arrays, bags, lists, nested tables, sets, and trees. Tosupport these techniques in database applications, PL/SQL provides the datatypesTABLE andVARRAY, whichallow you to declare index-by tables, nested tables and variable-size arrays. In this chapter, you learn howthose types let you reference and manipulate collections of data as whole objects. You also learn how thedatatypeRECORD lets you treat related but dissimilar data as a logical unit.

    This chapter discusses the following topics:

    "What Is a Collection?""Choosing Which PL/SQL Collection Types to Use""Defining Collection Types""Declaring PL/SQL Collection Variables""Initializing and Referencing Collections""Assigning Collections""Using PL/SQL Collections with SQL Statements""Using Collection Methods""Avoiding Collection Exceptions""Reducing Loop Overhead for Collections with Bulk Binds""What Is a Record?""Defining and Declaring Records""Initializing Records""Assigning Records""Manipulating Records"

    What Is a Collection?

    A collection is an ordered group of elements, all of the same type. It is a general concept that encompasseslists, arrays, and other familiar datatypes. Each element has a unique subscript that determines its position inthe collection.

    PL/SQL offers these collection types:

    z Index-by tables, also known asassociative arrays, let you look up elements using arbitrary numbersand strings for subscript values. (They are similar tohash tablesin other programming languages.)

    z Nested tableshold an arbitrary number of elements. They use sequential numbers as subscripts. You candefine equivalent SQL types, allowing nested tables to be stored in database tables and manipulated

    PL/SQL User's Guide and ReferenceRelease 2 (9.2)Part Number A96624-01

    Home BookList

    Contents Index Master

    IndexFeedback

    Page 1of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    2/50

    through SQL.

    z Varrays(short for variable-size arrays) hold a fixed number of elements (although you can change thenumber of elements at runtime). They use sequential numbers as subscripts. You can define equivalentSQL types, allowing varrays to be stored in database tables. They can be stored and retrieved throughSQL, but with less flexibility than nested tables.

    Although collections can have only one dimension, you can model multi-dimensional arrays by creating

    collections whose elements are also collections.

    To use collections in an application, you define one or more PL/SQL types, then define variables of thosetypes. You can define collection types in a procedure, function, or package. You can pass collection variablesas parameters, to move data between client-side applications and stored subprograms.

    To look up data that is more complex than single values, you can store PL/SQL records or SQL object types incollections. Nested tables and varrays can also be attributes of object types.

    Understanding Nested Tables

    Within the database, nested tables can be considered one-column database tables. Oracle stores the rows of a

    nested table in no particular order. But, when you retrieve the nested table into a PL/SQL variable, the rows aregiven consecutive subscripts starting at 1. That gives you array-like access to individual rows.

    PL/SQL nested tables are like one-dimensional arrays. You can model multi-dimensional arrays by creatingnested tables whose elements are also nested tables.

    Nested tables differ from arrays in two important ways:

    1. Arrays have a fixed upper bound, but nested tables are unbounded (seeFigure 5-1). So, the size of anested table can increase dynamically.

    Figure 5-1 Array versus Nested Table

    Text description of the illustration pls81016_array_versus_nested_table.gif

    z Arrays must bedense(have consecutive subscripts). So, you cannot delete individual elements from an

    array. Initially, nested tables are dense, but they can becomesparse(have nonconsecutive subscripts).So, you can delete elements from a nested table using the built-in procedureDELETE. That might leavegaps in the index, but the built-in function NEXT lets you iterate over any series of subscripts.

    Understanding Varrays

    Items of typeVARRAY are calledvarrays. They allow you to associate a single identifier with an entirecollection. This association lets you manipulate the collection as a whole and reference individualelements easily. To reference an element, you use standard subscripting syntax (seeFigure 5-2). Forexample,Gr ade(3) references the third element in varray Gr ades.

    Page 2of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    3/50

    Figure 5-2 Varray of Size 10

    Text description of the illustration pls81017_varray_of_size_10.gif

    A varray has a maximum size, which you must specify in its type definition. Its index has a fixed lowerbound of 1 and an extensible upper bound. For example, the current upper bound for varrayGr ades is 7,but you can extend it to 8, 9, 10, and so on. Thus, a varray can contain a varying number of elements,from zero (when empty) to the maximum specified in its type definition.

    Understanding Associative Arrays (Index-By Tables)

    Associative arrays are sets of key-value pairs, where each key is unique and is used to locate acorresponding value in the array. The key can be an integer or a string.

    Assigning a value using a key for the first time adds that key to the associative array. Subsequentassignments using the same key update the same entry. It is important to choose a key that is unique,

    either by using the primary key from a SQL table, or by concatenating strings together to form a uniquevalue.

    For example, here is the declaration of an associative array type, and two arrays of that type, using keysthat are strings:

    DECLARETYPE popul at i on_t ype I S TABLE OF NUMBER I NDEX BY VARCHAR2(64) ;count r y_popul at i on popul ati on_t ype;cont i nent _popul at i on popul at i on_t ype;howmany NUMBER;whi ch VARCHAR2( 64)

    BEGI Ncount r y_popul at i on( ' Gr eenl and' ) : = 100000;count r y_popul at i on( ' I cel and' ) : = 750000;howmany : = countr y_popul at i on( ' Gr eenl and' ) ;

    cont i nent _popul at i on( ' Aust r al i a' ) : = 30000000;cont i nent _popul at i on( ' Ant ar ct i ca' ) : = 1000; - - Cr eat es new ent r ycont i nent _popul at i on( ' Ant ar ct i ca' ) : = 1001; - - Repl aces pr evi ous

    val uewhi ch : = cont i nent _popul at i on. FI RST; - - Ret ur ns ' Ant ar ct i ca'

    - - as t hat comes f i rst al phabet i cal l y.whi ch : = cont i nent _popul at i on. LAST; - - Ret ur ns ' Aust r al i a'howmany : = cont i nent _popul at i on( cont i nent _popul at i on. LAST) ;

    - - Ret ur ns t he val ue cor r espondi ng t o t he l ast key, i n t hi s

    - - case t he popul at i on of Aust r al i a.END;/

    Associative arrays help you represent data sets of arbitrary size, with fast lookup for an individualelement without knowing its position within the array and without having to loop through all the arrayelements. It is like a simple version of a SQL table where you can retrieve values based on the primarykey. For simple temporary storage of lookup data, associative arrays let you avoid using the disk spaceand network operations required for SQL tables.

    Page 3of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    4/50

    Because associative arrays are intended for temporary data rather than storing persistent data, you cannotuse them with SQL statements such as I NSERT andSELECT I NTO. You can make them persistent for thelife of a database session by declaring the type in a package and assigning the values in a package body.

    How Globalization Settings Af fect VARCHAR2 Keys for Associative Arrays

    If settings for national language or globalization change during a session that uses associative arrays with

    VARCHAR2 key values, the program might encounter a runtime error. For example, changing theNLS_COMP or NLS_SORT initialization parameters within a session might cause methods such as NEXT andPRI OR to raise exceptions. If you need to change these settings during the session, make sure to set themback to their original values before performing further operations with these kinds of associative arrays.

    When you declare an associative array using a string as the key, the declaration must use aVARCHAR2,STRI NG, or LONGtype. You can use a different type, such asNCHAR or NVARCHAR2, as the key value toreference an associative array. You can even use a type such asDATE, as long as it can be converted toVARCHAR2 by theTO_CHAR function.

    However, you must be careful when using other types that the values used as keys are consistent andunique. For example, the string value ofSYSDATE might change if theNLS_DATE_FORMAT initialization

    parameter changes, so that ar r ay_el ement ( SYSDATE) does not produce the same result as before. TwodifferentNVARCHAR2 values might turn into the sameVARCHAR2 value (containing question marks insteadof certain national characters). In that case, ar r ay_el ement ( nat i onal _st r i ng1) andarr ay_el ement( nat i onal _st ri ng2) might refer to the same element.

    When you pass an associative array as a parameter to a remote database using a database link, the twodatabases can have different globalization settings. When the remote database performs operations suchasFI RST andNEXT, it uses its own character order even if that is different from the order where thecollection originated. If character set differences mean that two keys that were unique are not unique onthe remote database, the program receives aVALUE_ERROR exception.

    Choosing Which PL/SQL Collection Types to UseIf you already have code or business logic that uses some other language, you can usually translate thatlanguage's array and set types directly to PL/SQL collection types.

    z Arrays in other languages become VARRAYs in PL/SQL.

    z Sets and bags in other languages become nested tables in PL/SQL.

    z Hash tables and other kinds of unordered lookup tables in other languages become associativearrays in PL/SQL.

    When you are writing original code or designing the business logic from the start, you should considerthe strengths of each collection type to decide which is appropriate for each situation.

    Choosing Between Nested Tables and Associative Arrays

    Both nested tables and associative arrays (formerly known as index-by tables) use similar subscriptnotation, but they have different characteristics when it comes to persistence and ease of parameterpassing.

    Nested tables can be stored in a database column, but associative arrays cannot. Nested tables areappropriate for important data relationships that must be stored persistently.

    Page 4of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    5/50

    Associative arrays are appropriate for relatively small lookup tables where the collection can beconstructed in memory each time a procedure is called or a package is initialized. They are good forcollecting information whose volume is unknown beforehand, because there is no fixed limit on theirsize. Their index values are more flexible, because associative array subscripts can be negative, can benonsequential, and can use string values instead of numbers when appropriate.

    PL/SQL automatically converts between host arrays and associative arrays that use numeric key values.

    The most efficient way to pass collections to and from the database server is to use anonymous PL/SQLblocks to bulk-bind input and output host arrays to associative arrays.

    Choosing Between Nested Tables and Varrays

    Varrays are a good choice when the number of elements is known in advance, and when the elements areusually all accessed in sequence. When stored in the database, varrays retain their ordering andsubscripts.

    Each varray is stored as a single object, either inside the table of which it is a column (if the varray is lessthan 4KB) or outside the table but still in the same tablespace (if the varray is greater than 4KB). Youmust update or retrieve all elements of the varray at the same time, which is most appropriate when

    performing some operation on all the elements at once. But you might find it impractical to store andretrieve large numbers of elements this way.

    Nested tables can be sparse: you can delete arbitrary elements, rather than just removing an item fromthe end. Nested table data is stored out-of-line in astore table, a system-generated database tableassociated with the nested table. This makes nested tables suitable for queries and updates that onlyaffect some elements of the collection. You cannot rely on the order and subscripts of a nested tableremaining stable as the table is stored and retrieved, because the order and subscripts are not preservedwhen a nested table is stored in the database.

    Defining Collection Types

    To create collections, you define a collection type, then declare variables of that type. You can defineTABLE andVARRAY types in the declarative part of any PL/SQL block, subprogram, or package.

    Collections follow the same scoping and instantiation rules as other types and variables. In a block orsubprogram, collections are instantiated when you enter the block or subprogram and cease to exist whenyou exit. In a package, collections are instantiated when you first reference the package and cease toexist when you end the database session.

    Nested Tables

    For nested tables, use the syntax:

    TYPE t ype_name I S TABLE OF el ement_t ype [ NOT NULL] ;

    t ype_name is a type specifier used later to declare collections. For nested tables declared within PL/SQL,el ement_t ype is any PL/SQL datatype except:

    REF CURSOR

    Nested tables declared globally in SQL have additional restrictions on the element type. They cannot usethe following element types:

    Page 5of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    6/50

    BI NARY_I NTEGER, PLS_I NTEGERBOOLEANLONG, LONGRAWNATURAL, NATURALNPOSI TI VE, POSI TI VENREFCURSORSI GNTYPE

    STRI NG

    Varrays

    For varrays, use the syntax:

    TYPE t ype_name I S {VARRAY | VARYI NG ARRAY} ( si ze_ l i mi t )OF el ement_t ype [ NOT NULL] ;

    The meanings oft ype_name andel ement_t ype are the same as for nested tables.

    si ze_l i mi t is a positive integer literal representing the maximum number of elements in the array.When defining aVARRAY type, you must specify its maximum size. In the following example, you definea type that stores up to 366 dates:

    DECLARETYPE Cal endar I S VARRAY( 366) OF DATE;

    Associative Arrays

    For associative arrays (also known as index-by tables), use the syntax:

    TYPE t ype_name I S TABLE OF el ement_t ype [ NOT NULL]

    I NDEX BY [ BI NARY_I NTEGER | PLS_ I NTEGER | VARCHAR2( si ze_ l i mi t ) ] ;I NDEX BY key_t ype;

    The key_type can be numeric, either BI NARY_I NTEGER or PLS_I NTEGER. It can also beVARCHAR2 or oneof its subtypesVARCHAR, STRI NG, or LONG. You must specify the length of aVARCHAR2-based key, exceptfor LONGwhich is equivalent to declaring a key type ofVARCHAR2(32760) . The typesRAW, LONG RAW,ROWI D, CHAR, andCHARACTERare not allowed as keys for an associative array.

    An initialization clause is not required (or allowed).

    When you reference an element of an associative array that uses a VARCHAR2-based key, you can use

    other types, such asDATE orTI MESTAMP, as long as they can be converted toVARCHAR2 with theTO_CHARfunction.

    Index-by tables can store data using a primary key value as the index, where the key values are notsequential. In the example below, you store a single record in the index-by table, and its subscript is 7468rather than 1.

    DECLARETYPE EmpTabTyp I S TABLE OF emp%ROWTYPE

    I NDEX BY BI NARY_I NTEGER;emp_t ab EmpTabTyp;

    Page 6of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    7/50

    BEGI N/ * Retr i eve empl oyee recor d. */SELECT * I NTO emp_t ab( 7468) FROM emp WHERE empno = 7468;

    END;

    Defining SQL Types Equivalent to PL/SQL Collection Types

    To store nested tables and varrays inside database tables, you must also declare SQL types using theCREATE TYPE statement. The SQL types can be used as columns or as attributes of SQL object types.

    You can declare equivalent types within PL/SQL, or use the SQL type name in a PL/SQL variabledeclaration.

    Nested Table Example

    The following SQL*Plus script shows how you might declare a nested table in SQL, and use it as anattribute of an object type:

    CREATE TYPE CourseLi st AS TABLE OF VARCHAR2(10) - - def i ne t ype

    /CREATE TYPE Student AS OBJ ECT ( - - cr eat e obj ecti d_num I NTEGER( 4) ,name VARCHAR2( 25) ,address VARCHAR2( 35) ,st atus CHAR( 2) ,cour ses Cour seLi st ) - - decl ar e nest ed t abl e as at t r i but e

    /

    The identifier cour ses represents an entire nested table. Each element ofcour ses will store the codename of a college course such as ' Mat h 1020' .

    Varray Example

    The script below creates a database column that stores varrays. Each varray element contains aVARCHAR2.

    - - Each pr oj ect has a 16- char acter code name.- - We wi l l st ore up to 50 pr oj ects at a t i me i n a database col umn.CREATE TYPE Pr oj ect Li st AS VARRAY( 50) OF VARCHAR2( 16) ;/CREATE TABLE depar t ment ( - - cr eat e dat abase t abl e

    dept _i d NUMBER( 2) ,name VARCHAR2( 15) ,budget NUMBER( 11, 2) ,

    - - Each depart ment can have up t o 50 proj ect s.

    proj ects Proj ectLi st)/

    Declaring PL/SQL Collection Variables

    Once you define a collection type, you can declare variables of that type. You use the new type name inthe declaration, the same as with predefined types such as NUMBER and INTEGER.

    Example: Declaring Nested Tables, Varrays, and Associative Arrays

    Page 7of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    8/50

    DECLARETYPE nest ed_t ype I S TABLE OF VARCHAR2( 20) ;TYPE var r ay_t ype I S VARRAY( 50) OF I NTEGER;TYPE associ at i ve_ar r ay_t ype I S TABLE OF NUMBER

    I NDEXED BY BI NARY_I NTEGER;v1 nest ed_t ype;v2 var r ay_t ype;v3 associ at i ve_arr ay_t ype;

    %TYPE Example

    You can use%TYPE to specify the datatype of a previously declared collection, so that changing thedefinition of the collection automatically updates other variables that depend on the number of elementsor the element type:

    DECLARETYPE Pl at oon I S VARRAY( 20) OF Sol di er ;p1 Pl atoon;

    - - I f we change t he number of sol di ers i n a pl atoon, p2 wi l l- - r ef l ect t hat change when t hi s bl ock i s r ecompi l ed.

    p2 p1%TYPE;

    Example: Declaring a Procedure Parameter as a Nested Table

    You can declare collections as the formal parameters of functions and procedures. That way, you canpass collections to stored subprograms and from one subprogram to another. The following exampledeclares a nested table as a parameter of a packaged procedure:

    CREATE PACKAGE per sonnel ASTYPE St af f I S TABLE OF Empl oyee;. . .PROCEDURE awar d_bonuses ( member s I N St af f ) ;

    END personnel ;

    To call PERSONNEL. AWARD_BONUSES from outside the package, you declare a variable of typePERSONNEL. STAFF and pass that variable as the parameter.

    You can also specify a collection type in theRETURN clause of a function specification:

    DECLARETYPE Sal esFor ce I S VARRAY( 25) OF Sal esper son;FUNCTI ON t op_per f ormers ( n I NTEGER) RETURN Sal esForce I S . . .

    Example: Specifying Collect ion Element Types with %TYPE and %ROWTYPE

    To specify the element type, you can use%TYPE, which provides the datatype of a variable or databasecolumn. Also, you can use%ROWTYPE, which provides the rowtype of a cursor or database table. Twoexamples follow:

    DECLARETYPE EmpLi st I S TABLE OF emp. ename%TYPE; - - based on col umnCURSOR c1 I S SELECT * FROM dept ;TYPE DeptFi l e I S VARRAY( 20) OF c1%ROWTYPE; - - based on cur sor

    Page 8of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    9/50

    Example: VARRAY of Records

    In the next example, you use aRECORD type to specify the element type:

    DECLARETYPE AnEnt r y I S RECORD (

    t er m VARCHAR2( 20) ,meani ng VARCHAR2( 200) ) ;

    TYPE Gl ossar y I S VARRAY( 250) OF AnEnt r y;

    Example: NOT NULL Constraint on Collection Elements

    You can also impose aNOTNULL constraint on the element type:

    DECLARETYPE EmpLi st I S TABLE OF emp. empno%TYPE NOT NULL;

    Initializing and Referencing Collections

    Until you initialize it, a nested table or varray is atomically null: the collection itself is null, not itselements. To initialize a nested table or varray, you use aconstructor, a system-defined function with thesame name as the collection type. This function "constructs" collections from the elements passed to it.

    You must explicitly call a constructor for each varray and nested table variable. (Associative arrays, thethird kind of collection, do not use constructors.) Constructor calls are allowed wherever function callsare allowed.

    Example: Constructor for a Nested Table

    In the following example, you pass multiple elements to the constructor Cour seLi st ( ) , which returns a

    nested table containing those elements:

    DECLARETYPE CourseLi st I S TABLE OF VARCHAR2(16) ;my_cour ses Cour seLi st ;

    BEGI Nmy_courses : =

    Cour seLi st ( ' Econ 2010' , ' Acct 3401' , ' Mgmt 3100' ) ;END;

    Because a nested table does not have a declared maximum size, you can put as many elements in theconstructor as necessary.

    Example: Construc tor for a Varray

    In the next example, you pass three objects to constructor Proj ect Li st ( ) , which returns a varraycontaining those objects:

    DECLARETYPE Pr oj ect Li st I S VARRAY( 50) OF VARCHAR2(16) ;account i ng_pr oj ects Pr oj ect Li st ;

    BEGI Naccount i ng_proj ect s : =

    Page 9of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    10/50

    Pr oj ectLi st ( ' Expense Repor t ' , ' Out sourci ng' , ' Audi t i ng' ) ;END;

    You need not initialize the whole varray. For example, if a varray has a maximum size of 50, you canpass fewer than 50 elements to its constructor.

    Example: Collection Constructor Including Null Elements

    Unless you impose theNOTNULL constraint, you can pass null elements to a constructor. An examplefollows:

    BEGI Nmy_cour ses : = Cour seLi st ( ' Math 3010' , NULL, ' St at 3202' ) ;

    Example: Combining Collection Declaration and Constructor

    You can initialize a collection in its declaration, which is a good programming practice:

    DECLARETYPE CourseLi st I S TABLE OF VARCHAR2(16) ;my_cour ses Cour seLi st : =

    Cour seLi st ( ' Art 1111' , ' Hi st 3100' , ' Engl 2005' ) ;

    Example: Empty Varray Constructor

    If you call a constructor without arguments, you get an empty but non-null collection:

    DECLARETYPE Cl i entel e I S VARRAY( 100) OF Cust omer ;vi ps Cl i ent el e : = Cl i ent el e( ) ; - - i ni t i al i ze empt y varr ay

    BEGI NI F vi ps I S NOT NULL THEN - - condi t i on yi el ds TRUE

    . . .END I F;

    END;

    In this case, you can call the collection'sEXTENDmethod to add elements later.

    Example: Nested Table Constructor Within a SQL Statement

    In this example, you insert several scalar values and aCour seLi st nested table into theSOPHOMOREStable.

    BEGI NI NSERT I NTO sophomor es

    VALUES ( 5035, ' J anet Al var ez' , ' 122 Br oad St ' , ' FT' ,Cour seLi st ( ' Econ 2010' , ' Acct 3401' , ' Mgmt 3100' ) ) ;

    Example: Varray Constructor Within a SQL Statement

    In this example, you insert a row into database tableDEPARTMENT. The varray constructor Proj ectLi st( ) provides a value for columnPROJ ECTS.

    Page 10of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    11/50

    BEGI NI NSERT I NTO depart ment

    VALUES(60, ' Securi t y' , 750400,Pr oj ect Li st ( ' New Badges' , ' Tr ack Comput er s' , ' Check Exi t s' ) ) ;

    Referencing Collection Elements

    Every reference to an element includes a collection name and a subscript enclosed in parentheses. Thesubscript determines which element is processed. To reference an element, you specify its subscriptusing the syntax

    col l ect i on_name( subscr i pt )

    wheresubscr i pt is an expression that yields an integer in most cases, or aVARCHAR2 for associativearrays declared with strings as keys.

    The allowed subscript ranges are:

    z For nested tables, 1 .. 2**31.z For varrays, 1 .. si ze_ l i mi t , where you specify the limit in the declaration.

    z For associative arrays with a numeric key, -2**31 .. 2**31.

    z For associative arrays with a string key, the length of the key and number of possible valuesdepends on theVARCHAR2 length limit in the type declaration, and the database character set.

    Example: Referencing a Nested Table Element By Subscript

    This example shows how to reference an element in the nested tableNAMES:

    DECLARE

    TYPE Rost er I S TABLE OF VARCHAR2(15) ;names Rost er : = Rost er ( ' J Hami l ' , ' D Car uso' , ' R Si ngh' ) ;

    BEGI NFOR i I N names. FI RST . . names. LASTLOOP

    I F names( i ) = ' J Hami l ' THENNULL;

    END I F;END LOOP;

    END;

    Example: Passing a Nested Table Element as a Parameter

    This example shows that you can reference the elements of a collection in subprogram calls:

    DECLARETYPE Rost er I S TABLE OF VARCHAR2(15) ;names Rost er : = Rost er ( ' J Hami l ' , ' D Pi r o' , ' R Si ngh' ) ;i BI NARY_I NTEGER : = 2;

    BEGI Nver i f y_name( names( i ) ) ; - - cal l pr ocedur e

    END;

    Page 11of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    12/50

    Assigning Collections

    One collection can be assigned to another by an I NSERT, UPDATE, FETCH, or SELECT statement, anassignment statement, or a subprogram call.

    You can assign the value of an expression to a specific element in a collection using the syntax:

    col l ect i on_name( subscr i pt ) : = expr essi on;

    whereexpress i on yields a value of the type specified for elements in the collection type definition.

    Example: Datatype Compatibilit y

    This example shows that collections must have the same datatype for an assignment to work. Having thesame element type is not enough.

    DECLARETYPE Cl i entel e I S VARRAY( 100) OF Cust omer ;

    TYPE Vi ps I S VARRAY( 100) OF Cust omer ;- - These f i r st t wo var i abl es have the same datat ype.gr oup1 Cl i ent el e : = Cl i ent el e( . . . ) ;gr oup2 Cl i ent el e : = Cl i ent el e( . . . ) ;

    - - Thi s t hi r d var i abl e has a si mi l ar decl ar at i on,- - but i s not t he same type.

    gr oup3 Vi ps : = Vi ps( . . . ) ;BEGI N- - Al l owed because t hey have the same dat atype

    group2 : = gr oup1;- - Not al l owed because t hey have di f f erent datat ypes

    group3 : = gr oup2;END;

    Example: Assigning a Null Value to a Nested Table

    You assign an atomically null nested table or varray to a second nested table or varray. In this case, thesecond collection must be reinitialized:

    DECLARETYPE Cl i entel e I S TABLE OF VARCHAR2(64) ;- - Thi s nest ed t abl e has some val ues.gr oup1 Cl i ent el e : = Cl i ent el e( ' Cust omer 1' , ' Cust omer 2' ) ;

    - - Thi s nested t abl e i s not i ni t i al i zed ( "at omi cal l y nul l ") .gr oup2 Cl i ent el e;

    BEGI N- - At f i r st , t he t est I F gr oup1 I S NULL yi el ds FALSE.

    - - Then we assi gn a nul l nest ed t abl e t o gr oup1.group1 : = gr oup2;

    - - Now t he t est I F gr oup1 I S NULL yi el ds TRUE.- - We must use another const r uct or t o gi ve i t some val ues.END;

    In the same way, assigning the valueNULL to a collection makes it atomically null.

    Example: Possible Exceptions for Collection Assignments

    Page 12of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    13/50

    Assigning a value to a collection element can cause various exceptions:

    z If the subscript is null or is not convertible to the right datatype, PL/SQL raises the predefinedexceptionVALUE_ERROR. Usually, the subscript must be an integer. Associative arrays can also bedeclared to haveVARCHAR2 subscripts.

    z If the subscript refers to an uninitialized element, PL/SQL raisesSUBSCRI PT_BEYOND_COUNT.

    z

    If the collection is atomically null, PL/SQL raisesCOLLECTI ON_I S_NULL.

    DECLARETYPE Wor dLi st I S TABLE OF VARCHAR2(5) ;words WordLi st ;

    BEGI N/ * Assume execut i on cont i nues despi t e the rai sed except i ons. */

    - - Rai ses COLLECTI ON_I S_NULL. We haven' t used a const r uctor yet .- - Thi s except i on appl i es t o var r ays and nest ed tabl es, but not- - associ at i ve ar r ays whi ch don' t need a const r uct or .

    words( 1) : = 10;- - Af t er usi ng a const r uct or, we can assi gn val ues to the el ement s.

    words : = WordLi st ( 10, 20, 30) ;- - Any expr essi on t hat r eturns a VARCHAR2( 5) i s OK.

    wor ds( 1) : = ' yes' ;wor ds( 2) : = wor ds( 1) | | ' no' ;- - Rai ses VALUE_ERROR because t he assi gned val ue i s t oo l ong.

    words( 3) : = ' l onger t han 5 charact ers' ;- - Rai ses VALUE_ERROR because t he subscr i pt of a nest ed t abl e must- - be an i nt eger .

    wor ds( ' B' ) : = ' dunno' ;- - Rai ses SUBSCRI PT_BEYOND_COUNT because we onl y made 3 el ement s- - i n the const r uct or. To add new ones, we must cal l t he EXTEND- - met hod f i r st .

    words( 4) : = ' maybe' ;END;

    Comparing Collections

    You can check whether a collection is null, but not test whether two collections are the same. Conditionssuch as greater than, less than, and so on are also not allowed.

    Example: Checking if a Collection Is Null

    Nested tables and varrays can be atomically null, so they can be tested for nullity:

    DECLARETYPE St af f I S TABLE OF Empl oyee;members St af f ;

    BEGI N- - Condi t i on yi el ds TRUE because we haven' t used a const r uct or.I F members I S NULL THEN . . .

    END;

    Example: Comparing Two Collections

    Collections cannot be directly compared for equality or inequality. For instance, the following I Fcondition is not allowed:

    DECLARE

    Page 13of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    14/50

    TYPE Cl i ent el e I S TABLE OF VARCHAR2(64) ;gr oup1 Cl i ent el e : = Cl i ent el e( ' Cust omer 1' , ' Cust omer 2' ) ;gr oup2 Cl i ent el e : = Cl i ent el e( ' Cust omer 1' , ' Cust omer 3' ) ;

    BEGI N- - Equal i t y test causes compi l at i on er r or .

    I F gr oup1 = gr oup2 THEN. . .

    END I F;END;

    This restriction also applies to implicit comparisons. For example, collections cannot appear in aDI STI NCT, GROUPBY, or ORDERBY list.

    If you want to do such comparison operations, you must define your own notion of what it means forcollections to be equal or greater than, less than, and so on, and write one or more functions to examinethe collections and their elements and return a true or false value.

    Using PL/SQL Collections with SQL Statements

    Collections let you manipulate complex datatypes within PL/SQL. Your program can compute subscriptsto process specific elements in memory, and use SQL to store the results in database tables.

    Example: Creating a SQL Type Corresponding to a PL/SQL Nested Table

    In SQL*Plus, you can create SQL types whose definitions correspond to PL/SQL nested tables andvarrays:

    SQL> CREATE TYPE Cour seLi st AS TABLE OF VARCHAR2( 64) ;

    You can use these SQL types as columns in database tables:

    SQL> CREATE TABLE depar t ment (2 name VARCHAR2( 20) ,3 di r ect or VARCHAR2(20) ,4 of f i ce VARCHAR2(20) ,5 cour ses Cour seLi st )6 NESTED TABLE cour ses STORE AS cour ses_t ab;

    Each item in columnCOURSES is a nested table that will store the courses offered by a given department.TheNESTEDTABLE clause is required whenever a database table has a nested table column. The clauseidentifies the nested table and names a system-generated store table, in which Oracle stores the nestedtable data.

    Example: Insert ing a Nested Table into a Database Table

    Now, you can populate the database table. The table constructor provides values that all go into thesingle columnCOURSES:

    BEGI NI NSERT I NTO depart ment

    VALUES( ' Engl i sh' , ' Lynn Saunder s' , ' Br eakstone Hal l 205' ,CourseLi st ( ' Exposi t ory Wr i t i ng' ,

    ' Fi l m and Li terature' ,' Moder n Sci ence Fi ct i on' ,

    Page 14of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    15/50

    ' Di scur si ve Wr i t i ng' ,' Modern Engl i sh Gr ammar ' ,' I nt r oduct i on t o Shakespear e' ,' Modern Dr ama' ,' The Shor t St or y' ,' The Amer i can Novel ' ) ) ;

    END;

    Example: Retrieving a PL/SQL Nested Table from a Database Table

    You can retrieve all the courses offered by the English department into a PL/SQL nested table:

    DECLAREengl i sh_cour ses Cour seLi st ;

    BEGI NSELECT courses I NTO engl i sh_courses FROM depar t ment

    WHERE name = ' Engl i sh' ;END;

    Within PL/SQL, you can manipulate the nested table by looping through its elements, using methodssuch asTRI Mor EXTEND, and updating some or all of the elements. Afterwards, you can store the updatedtable in the database again.

    Example: Updating a Nested Table within a Database Table

    You can revise the list of courses offered by the English Department:

    DECLAREnew_cour ses Cour seLi st : =

    Cour seLi st ( ' Exposi t or y Wr i t i ng' ,' Fi l m and Li terat ure' ,' Di scursi ve Wr i t i ng' ,' Moder n Engl i sh Gr ammar ' ,' Real i sm and Nat ur al i sm' ,' I nt r oduct i on t o Shakespear e' ,' Moder n Dr ama' ,' The Shor t St or y' ,' The Ameri can Novel ' ,' 20t h- Cent ur y Poet r y' ,' Advanced Workshop i n Poet r y' ) ;

    BEGI NUPDATE depar t ment

    SET cour ses = new_cour ses WHERE name = ' Engl i sh' ;END;

    Some Varray ExamplesIn SQL*Plus, suppose you define object typePr oj ect , as follows:

    SQL> CREATE TYPE Pr oj ect AS OBJ ECT (2 proj ect _no NUMBER( 2) ,3 t i t l e VARCHAR2( 35) ,4 cost NUMBER( 7, 2) ) ;

    Next, you defineVARRAY typeProj ectLi st , which storesPr oj ect objects:

    Page 15of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    16/50

    SQL> CREATE TYPE Pr oj ect Li st AS VARRAY( 50) OF Pr oj ect ;

    Finally, you create relational tabledepart ment , which has a column of typeProj ectLi st , as follows:

    SQL> CREATE TABLE depar t ment (2 dept_i d NUMBER( 2) ,3 name VARCHAR2( 15) ,

    4 budget NUMBER( 11, 2) ,5 proj ects Proj ectLi st) ;

    Each item in columnproj ects is a varray that will store the projects scheduled for a given department.

    Now, you are ready to populate relational tabledepart ment . In the following example, notice howvarray constructor Proj ectLi st ( ) provides values for columnpr oj ects :

    BEGI NI NSERT I NTO depart ment

    VALUES( 30, ' Account i ng' , 1205700,Proj ect Li st ( Proj ect ( 1, ' Desi gn New Expense Repor t ' , 3250) ,

    Pr oj ect ( 2, ' Out sour ce Payr ol l ' , 12350) ,Proj ect ( 3, ' Eval uat e Mer ger Proposal ' , 2750) ,Pr oj ect ( 4, ' Audi t Account s Payabl e' , 1425) ) ) ;

    I NSERT I NTO depart mentVALUES( 50, ' Mai ntenance' , 925300,

    Proj ectLi st ( Pr oj ect( 1, ' Repai r Leak i n Roof ' , 2850) ,Pr oj ect ( 2, ' I nst al l New Door Locks' , 1700) ,Proj ect ( 3, ' Wash Fr ont Wi ndows' , 975) ,Pr oj ect ( 4, ' Repai r Faul t y Wi r i ng' , 1350) ,Pr oj ect ( 5, ' Wi nt er i ze Cool i ng Syst em' , 1125) ) ) ;

    I NSERT I NTO depart mentVALUES(60, ' Securi t y' , 750400,

    Proj ectLi st ( Proj ect ( 1, ' I ssue New Empl oyee Badges' , 13500) ,Pr oj ect ( 2, ' Fi nd Mi ssi ng I C Chi ps' , 2750) ,Proj ect ( 3, ' Upgr ade Al ar m System' , 3350) ,Pr oj ect ( 4, ' I nspect Emer gency Exi t s' , 1900) ) ) ;

    END;

    In the following example, you update the list of projects assigned to the Security Department:

    DECLAREnew_pr oj ect s Pr oj ect Li st : =

    Proj ect Li st ( Proj ect ( 1, ' I ssue New Empl oyee Badges' , 13500) ,Proj ect ( 2, ' Devel op New Pat r ol Pl an' , 1250) ,Proj ect ( 3, ' I nspect Emer gency Exi t s' , 1900) ,Proj ect ( 4, ' Upgr ade Al ar m System' , 3350) ,Pr oj ect ( 5, ' Anal yze Local Cr i me St at s' , 825) ) ;

    BEGI NUPDATE depar t mentSET proj ect s = new_proj ect s WHERE dept _i d = 60;

    END;

    In the next example, you retrieve all the projects for the Accounting Department into a local varray:

    DECLAREmy_pr oj ect s Proj ect Li st ;

    BEGI N

    Page 16of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    17/50

    SELECT proj ect s I NTO my_pr oj ect s FROM depar t mentWHERE dept _i d = 30;

    END;

    In the final example, you delete the Accounting Department and its project list from tabledepart ment :

    BEGI N

    DELETE FROM depar t ment WHERE dept _i d = 30;END;

    Manipulating Individual Collection Elements with SQL

    By default, SQL operations store and retrieve whole collections rather than individual elements. Tomanipulate the individual elements of a collection with SQL, use theTABLE operator. TheTABLE operatoruses a subquery to extract the varray or nested table, so that the I NSERT, UPDATE, or DELETE statementapplies to the nested table rather than the top-level table.

    Example: Inserting an Element into a Nested Table with SQL

    In the following example, you add a row to the History Department nested table stored in columnCOURSES:

    BEGI N- - The TABLE oper ator makes t he st atement appl y t o t he nest ed- - t abl e f r omt he ' Hi st or y' r ow of t he DEPARTMENT t abl e.

    I NSERT I NTOTABLE( SELECT cour ses FROM depar t ment WHERE name = ' Hi st or y' )VALUES( ' Modern Chi na' ) ;

    END;

    Example: Updating Elements Inside a Nested Table with SQL

    In the next example, you abbreviate the names for some courses offered by the Psychology Department:

    BEGI NUPDATE TABLE( SELECT cour ses FROM depart ment

    WHERE name = ' Psychol ogy' )SET cr edi t s = cr edi t s + adj ust mentWHERE course_no I N ( 2200, 3540) ;

    END;

    Example: Retrieving a Single Element from a Nested Table with SQL

    In the following example, you retrieve the title of a specific course offered by the History Department:

    DECLAREmy_t i t l e VARCHAR2(64) ;

    BEGI N- - We know t hat t here i s one hi st ory cour se wi t h ' Et r uscan'- - i n t he t i t l e. Thi s query ret r i eves the compl et e t i t l e- - f r om t he nest ed t abl e of cour ses f or t he Hi st or y depar t ment .

    SELECT t i t l e I NTO my_t i t l eFROM

    TABLE( SELECT cour ses FROM depar t ment WHERE name = ' Hi st or y' )

    Page 17of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    18/50

    WHERE name LI KE ' %Et r uscan%' ;END;

    Example: Deleting Elements from a Nested Table with SQL

    In the next example, you delete all 5-credit courses offered by the English Department:

    BEGI NDELETE TABLE( SELECT cour ses FROM depar t ment

    WHERE name = ' Engl i sh' )WHERE cr edi t s = 5;

    END;

    Example: Retrieving Elements from a Varray with SQL

    In the following example, you retrieve the title and cost of the Maintenance Department's fourth projectfrom the varray columnproj ects :

    DECLARE

    my_cost NUMBER( 7, 2) ;my_t i t l e VARCHAR2(35) ;

    BEGI NSELECT cost , t i t l e I NTO my_cost , my_t i t l e

    FROM TABLE( SELECT proj ect s FROM depar t mentWHERE dept _i d = 50)

    WHERE pr oj ect _no = 4;. . .

    END;

    Example: Performing INSERT, UPDATE, and DELETE Operations on a Varray with SQL

    Currently, you cannot reference the individual elements of a varray in an I NSERT, UPDATE, or DELETEstatement. You must retrieve the entire varray, use PL/SQL procedural statements to add, delete, orupdate its elements, and then store the changed varray back in the database table.

    In the following example, stored procedureADD_PROJ ECT inserts a new project into a department'sproject list at a given position:

    CREATE PROCEDURE add_pr oj ect (dept _no I N NUMBER,new_pr oj ect I N Proj ect ,posi t i on I N NUMBER) ASmy_pr oj ect s Proj ect Li st ;

    BEGI N

    SELECT proj ect s I NTO my_pr oj ect s FROM depar t mentWHERE dept_no = dept _i d FOR UPDATE OF pr oj ect s;my_proj ects. EXTEND; - - make r oom f or new pr oj ect/ * Move var r ay el ement s f orward. */FOR i I N REVERSE posi t i on. . my_proj ect s. LAST - 1 LOOP

    my_pr oj ect s( i + 1) : = my_pr oj ect s( i ) ;END LOOP;my_pr oj ect s( posi t i on) : = new_proj ect ; - - add new pr oj ectUPDATE depar t ment SET proj ect s = my_pr oj ect s

    WHERE dept _no = dept _i d;END add_proj ect ;

    Page 18of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    19/50

    The following stored procedure updates a given project:

    CREATE PROCEDURE updat e_pr oj ect (dept _no I N NUMBER,pr oj _no I N NUMBER,new_t i t l e I N VARCHAR2 DEFAULT NULL,new_cost I N NUMBER DEFAULT NULL) ASmy_pr oj ect s Proj ect Li st ;

    BEGI NSELECT proj ect s I NTO my_pr oj ect s FROM depar t mentWHERE dept_no = dept _i d FOR UPDATE OF pr oj ect s;

    / * Fi nd pr oj ect , updat e i t , t hen exi t l oop i mmedi at el y. */FOR i I N my_proj ects. FI RST. . my_proj ect s. LAST LOOP

    I F my_pr oj ect s( i ) . pr oj ect _no = pr oj _no THENI F new_t i t l e I S NOT NULL THEN

    my_proj ects( i ) . t i t l e : = new_t i t l e;END I F;I F new_cost I S NOT NULL THEN

    my_pr oj ect s( i ) . cost : = new_cost ;END I F;EXI T;

    END I F;END LOOP;

    UPDATE depar t ment SET proj ect s = my_pr oj ect sWHERE dept _no = dept _i d;

    END updat e_proj ect ;

    Example: Performing INSERT, UPDATE, and DELETE Operations on PL/SQL NestedTables

    To perform DML operations on a PL/SQL nested table, use the operatorsTABLE andCAST. This way, youcan do set operations on nested tables using SQL notation, without actually storing the nested tables inthe database.

    The operands ofCAST are PL/SQL collection variable and a SQL collection type (created by theCREATE

    TYPE statement). CAST converts the PL/SQL collection to the SQL type.

    The following example counts the number of differences between a revised course list and the original(notice that the number of credits for course 3720 changed from 4 to 3):

    DECLAREr evi sed Cour seLi st : =

    Cour seLi st ( Cour se( 1002, ' Exposi t or y Wr i t i ng' , 3) ,Course(2020, ' Fi l m and Li t er at ur e' , 4) ,Cour se( 2810, ' Di scur si ve Wr i t i ng' , 4) ,Cour se( 3010, ' Modern Engl i sh Gr ammar ' , 3) ,Cour se(3550, ' Real i sm and Nat ur al i sm' , 4) ,Cour se(3720, ' I nt r oduct i on t o Shakespear e' , 3) ,Cour se( 3760, ' Modern Dr ama' , 4) ,Cour se(3822, ' The Shor t St or y' , 4) ,Cour se( 3870, ' The Ameri can Novel ' , 5) ,Cour se(4210, ' 20t h- Cent ur y Poet r y' , 4) ,Cour se( 4725, ' Advanced Workshop i n Poet r y' , 5) ) ;

    num_changed I NTEGER;BEGI N

    SELECT COUNT( *) I NTO num_changedFROM TABLE(CAST( r evi sed AS Cour seLi st ) ) new,TABLE( SELECT cour ses FROM depar t ment

    WHERE name = ' Engl i sh' ) AS ol dWHERE new. cour se_no = ol d. cour se_no AND

    Page 19of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    20/50

    ( new. t i t l e ! = ol d. t i t l e OR new. credi t s ! = ol d. credi t s) ;dbms_out put . put _l i ne( num_changed) ;

    END;

    Using Multi level Collections

    In addition to collections of scalar or object types, you can also create collections whose elements are

    collections. For example, you can create a nested table of varrays, a varray of varrays, a varray of nestedtables, and so on.

    When creating a nested table of nested tables as a column in SQL, check the syntax of theCREATE TABLEstatement to see how to define the storage table.

    Here are some examples showing the syntax and possibilities for multilevel collections.

    Multilevel VARRAY Example

    decl ar et ype t1 i s var r ay( 10) of i nt eger ;t ype nt 1 i s var r ay(10) of t 1; - - mul t i l evel var r ay t ype

    va t 1 : = t 1( 2, 3, 5) ;- - i ni t i al i ze mul t i l evel varr aynva nt 1 : = nt 1( va, t 1( 55, 6, 73) , t 1( 2, 4) , va) ;i i nt eger;va1 t 1;

    begi n- - mul t i l evel accessi : = nva( 2) ( 3) ; - - i wi l l get val ue 73dbms_out put . put _l i ne( i ) ;- - add a new varr ay el ement t o nvanva. extend;

    nva( 5) : = t 1( 56, 32) ;- - r epl ace an i nner var r ay el ement

    nva( 4) : = t 1( 45, 43, 67, 43345) ;- - r epl ace an i nner i nt eger el ementnva( 4) ( 4) : = 1; - - r epl aces 43345 wi t h 1

    - - add a new el ement t o t he 4th var r ay el ement- - and st ore i nt eger 89 i nt o i t .nva( 4) . extend;nva( 4) ( 5) : = 89;

    end;/

    Multilevel Nested Table Example

    decl ar e

    t ype tb1 i s t abl e of var char 2( 20) ;t ype nt b1 i s t abl e of t b1; - - t abl e of t abl e el ement st ype t v1 i s var r ay(10) of i nt eger ;t ype nt b2 i s t abl e of t v1; - - t abl e of var r ay el ement s

    vt b1 t b1 : = t b1( ' one' , ' t hree' ) ;vnt b1 ntb1 : = nt b1( vt b1) ;vnt b2 nt b2 : = nt b2( t v1( 3, 5) , t v1( 5, 7, 3) ) ; - - t abl e of var r ay

    el ementsbegi nvnt b1. ext end;vnt b1( 2) : = vnt b1( 1) ;

    Page 20of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    21/50

    - - del et e t he f i r st el ement i n vnt b1vnt b1. del et e( 1) ;- - del et e t he f i rst st ri ng f romt he second t abl e i n t he nest ed

    t abl evnt b1( 2) . del et e( 1) ;

    end;/

    Multilevel Associative Array Example

    decl ar et ype t b1 i s t abl e of i nt eger i ndex by bi nar y_i nt eger ;- - t he f ol l owi ng i s i ndex- by t abl e of i ndex- by t abl est ype nt b1 i s t abl e of t b1 i ndex by bi nar y_i nt eger ;t ype va1 i s var r ay(10) of var char 2( 20) ;- - t he f ol l owi ng i s i ndex- by t abl e of var r ay el ement st ype nt b2 i s t abl e of va1 i ndex by bi nary_i nt eger;

    v1 va1 : = va1( ' hel l o' , ' worl d' ) ;v2 nt b1;v3 nt b2;v4 t b1;v5 t b1; - - empt y tabl e

    begi nv4( 1) : = 34;v4(2) : = 46456;v4(456) : = 343;v2( 23) : = v4;v3( 34) : = va1( 33, 456, 656, 343) ;

    - - assi gn an empt y t abl e to v2( 35) and t r y agai nv2( 35) : = v5;v2( 35) ( 2) : = 78; - - i t wor ks now

    end;/

    Example of Multilevel Collections and Bulk SQL

    cr eat e t ype t 1 i s var r ay(10) of i nt eger ;/cr eat e t abl e t ab1 ( c1 t 1) ;

    i nser t i nt o t ab1 val ues ( t 1( 2, 3, 5) ) ;i nsert i nt o t ab1 val ues ( t 1( 9345, 5634, 432453) ) ;

    decl ar et ype t 2 i s t abl e of t 1;v2 t 2;

    begi nsel ect c1 BULK COLLECT I NTO v2 f r om t ab1;dbms_out put . put _l i ne( v2. count ) ; - - pr i nt s 2

    end;/

    Using Collection Methods

    The following collection methods help generalize code, make collections easier to use, and make yourapplications easier to maintain:

    Page 21of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    22/50

    EXISTSCOUNTLIMITFIRST and LASTPRIOR and NEXTEXTENDTRIM

    DELETE

    A collection method is a built-in function or procedure that operates on collections and is called usingdot notation. The syntax follows:

    col l ect i on_name. method_name[ ( par ameters) ]

    Collection methods cannot be called from SQL statements. Also, EXTENDandTRI Mcannot be used withassociative arrays. EXI STS, COUNT, LI MI T, FI RST, LAST, PRI OR, andNEXT are functions; EXTEND,TRI M,andDELETE are procedures. EXI STS, PRI OR, NEXT,TRI M, EXTEND, andDELETE take parameterscorresponding to collection subscripts, which are usually integers but can also be strings for associativearrays.

    Only EXI STS can be applied to atomically null collections. If you apply another method to suchcollections, PL/SQL raisesCOLLECTI ON_I S_NULL.

    Checking If a Collection Element Exists (EXISTS Method)

    EXI STS(n) returnsTRUE if thenth element in a collection exists. Otherwise, EXI STS(n) returnsFALSE.Mainly, you useEXI STS withDELETE to maintain sparse nested tables. Y ou can also useEXI STS to avoidraising an exception when you reference a nonexistent element. In the following example, PL/SQLexecutes the assignment statement only if element i exists:

    I F cour ses. EXI STS( i ) THEN cour ses( i ) : = new_cour se; END I F;

    When passed an out-of-range subscript, EXI STS returnsFALSE instead of raisingSUBSCRI PT_OUTSI DE_LI MI T.

    Counting the Elements in a Collection (COUNT Method)

    COUNT returns the number of elements that a collection currently contains. For instance, if varrayproj ects contains 25 elements, the following I F condition is true:

    I F proj ect s. COUNT = 25 THEN . . .

    COUNT is useful because the current size of a collection is not always known. For example, if you fetch acolumn of Oracle data into a nested table, how many elements does the table contain? COUNT gives youthe answer.

    You can useCOUNT wherever an integer expression is allowed. In the next example, you useCOUNT tospecify the upper bound of a loop range:

    FOR i I N 1. . cour ses. COUNT LOOP . . .

    Page 22of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    23/50

    For varrays, COUNT always equalsLAST. For nested tables,COUNT normally equalsLAST. But, if youdelete elements from the middle of a nested table, COUNT becomes smaller thanLAST.

    When tallying elements, COUNT ignores deleted elements.

    Checking the Maximum Size of a Collection (LIMIT Method)

    For nested tables and associative arrays, which have no maximum size, LI MI T returnsNULL. For varrays,LI MI T returns the maximum number of elements that a varray can contain (which you must specify in itstype definition, and can change later with theTRI MandEXTENDmethods). For instance, if the maximumsize of varray PROJ ECTS is 25 elements, the following I F condition is true:

    I F pr oj ect s. LI MI T = 25 THEN . . .

    You can useLI MI T wherever an integer expression is allowed. In the following example, you useLI MI Tto determine if you can add 15 more elements to varray pr oj ects :

    I F ( pr oj ect s. COUNT + 15) < pr oj ect s. LI MI T THEN . . .

    Finding the First or Last Collection Element (FIRST and LAST Methods)

    FI RST andLAST return the first and last (smallest and largest) index numbers in a collection. For anassociative array withVARCHAR2 key values, the lowest and highest key values are returned; ordering isbased on the binary values of the characters in the string, unless theNLS_COMP initialization parameter isset toANSI , in which case the ordering is based on the locale-specific sort order specified by theNLS_SORT initialization parameter.

    If the collection is empty,FI RST andLAST returnNULL.

    If the collection contains only one element, FI RST andLAST return the same index value:

    I F cour ses. FI RST = cour ses. LAST THEN . . . - - onl y one el ement

    The next example shows that you can useFI RST andLAST to specify the lower and upper bounds of aloop range provided each element in that range exists:

    FOR i I N cour ses. FI RST. . cour ses. LAST LOOP . . .

    In fact, you can useFI RST or LAST wherever an integer expression is allowed. In the following example,you useFI RST to initialize a loop counter:

    i : = cour ses. FI RST;WHI LE i I S NOT NULL LOOP . . .

    For varrays, FI RST always returns 1 andLAST always equalsCOUNT. For nested tables, FI RST normallyreturns 1. But, if you delete elements from the beginning of a nested table, FI RST returns a number largerthan 1. Also for nested tables, LAST normally equalsCOUNT. But, if you delete elements from the middleof a nested table, LAST becomes larger thanCOUNT.

    When scanning elements, FI RST andLAST ignore deleted elements.

    Page 23of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    24/50

    Looping Through Collection Elements (PRIOR and NEXT Methods)

    PRI OR(n) returns the index number that precedes indexn in a collection.NEXT( n) returns the indexnumber that succeeds indexn. Ifn has no predecessor, PRI OR( n) returnsNULL. Likewise, ifn has nosuccessor, NEXT( n) returnsNULL.

    For associative arrays withVARCHAR2 keys, these methods return the appropriate key value; ordering is

    based on the binary values of the characters in the string, unless theNLS_COMP initialization parameter isset toANSI , in which case the ordering is based on the locale-specific sort order specified by theNLS_SORT initialization parameter.

    These methods are more reliable than looping through a fixed set of subscript values, because elementsmight be inserted or deleted from the collection during the loop. This is especially true for associativearrays, where the subscripts might not be in consecutive order and so the sequence of subscripts might be(1,2,4,8,16) or ('A','E','I','O','U').

    PRI OR andNEXT do not wrap from one end of a collection to the other. For example, the followingstatement assignsNULL ton because the first element in a collection has no predecessor:

    n : = cour ses. PRI OR( cour ses. FI RST); - - assi gns NULL t o n

    PRI OR is the inverse ofNEXT. For instance, if element i exists, the following statement assigns element i to itself:

    proj ects( i ) : = pr oj ects. PRI OR( pr oj ects. NEXT( i ) ) ;

    You can usePRI OR or NEXT to traverse collections indexed by any series of subscripts. In the followingexample, you useNEXT to traverse a nested table from which some elements have been deleted:

    i : = cour ses. FI RST; - - get subscri pt of f i r st el ementWHI LE i I S NOT NULL LOOP

    - - do somet hi ng wi t h cour ses( i )i : = cour ses. NEXT( i ) ; - - get subscr i pt of next el ement

    END LOOP;

    When traversing elements, PRI OR andNEXT ignore deleted elements.

    Increasing the Size of a Collection (EXTEND Method)

    To increase the size of a nested table or varray, useEXTEND. You cannot useEXTENDwith index-bytables.

    This procedure has three forms:

    z EXTENDappends one null element to a collection.

    z EXTEND( n) appendsn null elements to a collection.

    z EXTEND( n, i ) appendsn copies of the i th element to a collection.

    For example, the following statement appends 5 copies of element 1 to nested tablecour ses:

    Page 24of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    25/50

    cour ses. EXTEND( 5, 1) ;

    You cannot useEXTEND to initialize an atomically null collection. Also, if you impose theNOTNULLconstraint on aTABLE or VARRAY type, you cannot apply the first two forms ofEXTEND to collections ofthat type.

    EXTENDoperates on the internal size of a collection, which includes any deleted elements. So, ifEXTENDencounters deleted elements, it includes them in its tally. PL/SQL keeps placeholders for deletedelements so that you can replace them if you wish. Consider the following example:

    DECLARETYPE CourseLi st I S TABLE OF VARCHAR2(10) ;cour ses Cour seLi st ;

    BEGI Ncour ses : = Cour seLi st ( ' Bi ol 4412' , ' Psyc 3112' , ' Ant h 3001' ) ;cour ses. DELETE( 3) ; - - del et e el ement 3/ * PL/ SQL keeps a pl acehol der f or el ement 3. So, t he

    next st at ement appends el ement 4, not el ement 3. */cour ses. EXTEND; - - append one nul l el ement/ * Now el ement 4 exi st s, so t he next st atement does

    not r ai se SUBSCRI PT_BEYOND_COUNT. */cour ses( 4) : = ' Engl 2005' ;

    When it includes deleted elements, the internal size of a nested table differs from the values returned byCOUNT andLAST. For instance, if you initialize a nested table with five elements, then delete elements 2and 5, the internal size is 5, COUNT returns 3, andLAST returns 4. All deleted elements (whether leading,in the middle, or trailing) are treated alike.

    Decreasing the Size of a Collection (TRIM Method)

    This procedure has two forms:

    z TRI Mremoves one element from the end of a collection.

    z TRI M( n) removesn elements from the end of a collection.

    For example, this statement removes the last three elements from nested tablecour ses:

    cour ses. TRI M( 3) ;

    Ifn is too large,TRI M( n) raisesSUBSCRI PT_BEYOND_COUNT.

    TRI Moperates on the internal size of a collection. So, ifTRI Mencounters deleted elements, it includes

    them in its tally. Consider the following example:

    DECLARETYPE CourseLi st I S TABLE OF VARCHAR2(10) ;cour ses Cour seLi st ;

    BEGI Ncour ses : = Cour seLi st ( ' Bi ol 4412' , ' Psyc 3112' , ' Ant h 3001' ) ;cour ses. DELETE( cour ses. LAST) ; - - del ete el ement 3/ * At t hi s poi nt , COUNT equal s 2, t he number of val i d

    el ement s r emai ni ng. So, you mi ght expect t he nextst atement t o empty t he nest ed t abl e by t r i mmi ngel ement s 1 and 2. I nst ead, i t t r i ms val i d el ement 2

    Page 25of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    26/50

    and del eted el ement 3 because TRI M i ncl udes del etedel ement s i n i t s t al l y. */

    cour ses. TRI M( cour ses. COUNT) ;dbms_out put . put _l i ne( cour ses( 1) ) ; - - pr i nt s ' Bi ol 4412'

    In general, do not depend on the interaction betweenTRI MandDELETE. It is better to treat nested tableslike fixed-size arrays and use only DELETE, or to treat them like stacks and use onlyTRI MandEXTEND.

    PL/SQL does not keep placeholders for trimmed elements. So, you cannot replace a trimmed elementsimply by assigning it a new value.

    Deleting Collection Elements (DELETE Method)

    This procedure has various forms:

    z DELETE removes all elements from a collection.

    z DELETE( n) removes thenth element from an associative array with a numeric key or a nestedtable. If the associative array has a string key, the element corresponding to the key value is

    deleted. Ifn is null, DELETE( n) does nothing.z DELETE( m, n) removes all elements in the rangem. . n from an associative array or nested table. If

    mis larger thann or ifmor n is null, DELETE( m, n) does nothing.

    For example:

    BEGI Ncour ses. DELETE( 2) ; - - del etes el ement 2cour ses. DELETE( 7, 7) ; - - del etes el ement 7cour ses. DELETE( 6, 3) ; - - does not hi ngcour ses. DELETE( 3, 6) ; - - del etes el ement s 3 t hr ough 6

    pr oj ect s. DELETE; - - del et es al l el ement s

    ni cknames. DELETE( ' Chi p' ) ; - - del etes el ement denoted by t hi s keyni cknames. DELETE( ' Buf f y' , ' Fl uf f y' ) ; - - del et es el ement s wi t h keys

    - - i n t hi s al phabet i c rangeEND;

    Varrays are dense, so you cannot delete their individual elements.

    If an element to be deleted does not exist, DELETE simply skips it; no exception is raised. PL/SQL keepsplaceholders for deleted elements. So, you can replace a deleted element simply by assigning it a newvalue.

    DELETE lets you maintain sparse nested tables. In the following example, you retrieve nested tablepr ospect s into a temporary table, prune it, then store it back in the database:

    DECLAREmy_pr ospect s ProspectLi st ;r evenue NUMBER;

    BEGI NSELECT prospect s I NTO my_pr ospect s FROM cust omers WHERE . . .FOR i I N my_pr ospect s. FI RST. . my_pr ospect s. LAST LOOP

    est i mat e_r evenue( my_pr ospect s( i ) , r evenue) ; - - cal l pr ocedur eI F r evenue < 25000 THEN

    Page 26of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    27/50

    my_prospect s. DELETE( i ) ;END I F;

    END LOOP;UPDATE cust omer s SET pr ospect s = my_pr ospect s WHERE . . .

    The amount of memory allocated to a nested table can increase or decrease dynamically. As you deleteelements, memory is freed page by page. If you delete the entire table, all the memory is freed.

    Applying Methods to Col lection Parameters

    Within a subprogram, a collection parameter assumes the properties of the argument bound to it. So, youcan apply the built-in collection methods (FI RST, LAST, COUNT, and so on) to such parameters. In thefollowing example, a nested table is declared as the formal parameter of a packaged procedure:

    CREATE PACKAGE per sonnel ASTYPE St af f I S TABLE OF Empl oyee;. . .PROCEDURE awar d_bonuses ( member s I N St af f ) ;

    END personnel ;CREATE PACKAGE BODY per sonnel AS

    . . .PROCEDURE awar d_bonuses ( members I N St af f ) I SBEGI N

    . . .I F member s. COUNT > 10 THEN - - appl y met hod

    . . .END I F;

    END;END personnel ;

    Note: For varray parameters, the value ofLI MI T is always derived from the parameter type definition,regardless of the parameter mode.

    Avoiding Collection Except ions

    In most cases, if you reference a nonexistent collection element, PL/SQL raises a predefined exception.Consider the following example:

    DECLARETYPE NumLi st I S TABLE OF NUMBER;nums NumLi st ; - - at omi cal l y nul l

    BEGI N/ * Assume execut i on cont i nues despi t e the rai sed except i ons. */nums( 1) : = 1; - - r ai ses COLLECTI ON_I S_NULL ( 1)nums : = NumLi st ( 1, 2) ; - - i ni t i al i ze t abl e

    nums( NULL) : = 3 - - r ai ses VALUE_ERROR ( 2)nums( 0) : = 3; - - r ai ses SUBSCRI PT_OUTSI DE_LI MI T ( 3)nums( 3) : = 3; - - r ai ses SUBSCRI PT_BEYOND_COUNT ( 4)nums. DELETE(1) ; - - del ete el ement 1I F nums( 1) = 1 THEN . . . - - r ai ses NO_DATA_FOUND ( 5)

    In the first case, the nested table is atomically null. In the second case, the subscript is null. In the thirdcase, the subscript is outside the legal range. In the fourth case, the subscript exceeds the number ofelements in the table. In the fifth case, the subscript designates a deleted element.

    Page 27of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    28/50

    The following list shows when a given exception is raised:

    In some cases, you can pass invalid subscripts to a method without raising an exception. For instance,when you pass a null subscript to procedureDELETE, it does nothing. Also, you can replace deletedelements without raisingNO_DATA_FOUND, as the following example shows:

    DECLARE

    TYPE NumLi st I S TABLE OF NUMBER;nums NumLi st : = NumLi st ( 10, 20, 30) ; - - i ni t i al i ze t abl eBEGI N

    nums. DELETE( - 1) ; - - does not r ai se SUBSCRI PT_OUTSI DE_LI MI Tnums. DELETE( 3) ; - - del ete 3rd el ementdbms_out put . put _l i ne(nums. COUNT); - - pri nt s 2nums( 3) : = 30; - - al l owed; does not rai se NO_DATA_FOUNDdbms_out put . put _l i ne(nums. COUNT); - - pri nt s 3

    END;

    Packaged collection types and local collection types are never compatible. For example, suppose youwant to call the following packaged procedure:

    CREATE PACKAGE pkg1 ASTYPE NumLi st I S VARRAY( 25) OF NUMBER( 4) ;PROCEDURE del et e_emps ( emp_l i st NumLi st ) ;

    END pkg1;

    CREATE PACKAGE BODY pkg1 ASPROCEDURE del ete_emps ( emp_l i st NumLi st ) I S . . .. . .

    END pkg1;

    When you run the PL/SQL block below, the second procedure call fails with awrong number or types ofargumentserror. That is because the packaged and local VARRAY types are incompatible even though

    their definitions are identical.DECLARE

    TYPE NumLi st I S VARRAY( 25) OF NUMBER( 4) ;emps pkg1. NumLi st : = pkg1. NumLi st ( 7369, 7499) ;emps2 NumLi st : = NumLi st ( 7521, 7566) ;

    BEGI Npkg1. del et e_emps( emps) ;pkg1. del ete_emps( emps2) ; - - causes a compi l at i on err or

    END;

    Collection Exception Raised when...

    COLLECTI ON_I S_NULL you try to operate on an atomically null collection.

    NO_DATA_FOUND a subscript designates an element that was deleted, or a nonexistent elemenan associative array.

    SUBSCRI PT_BEYOND_COUNT a subscript exceeds the number of elements in a collection.SUBSCRI PT_OUTSI DE_LI MI Ta subscript is outside the allowed range.

    VALUE_ERROR a subscript is null or not convertible to the key type. This exception mightif the key is defined as aPLS_I NTEGER range, and the subscript is outside trange.

    Page 28of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    29/50

    Reducing Loop Overhead for Collections with Bulk Binds

    AsFigure 5-3shows, the PL/SQL engine executes procedural statements but sends SQL statements tothe SQL engine, which executes the SQL statements and, in some cases, returns data to the PL/SQLengine.

    Figure 5-3 Context Switching

    Text description of the illustration pls81027_context_switching.gif

    Too many context switches between the PL/SQL and SQL engines can harm performance. That canhappen when a loop executes a separate SQL statement for each element of a collection, specifying thecollection element as a bind variable. For example, the followingDELETE statement is sent to the SQLengine with each iteration of theFOR loop:

    DECLARETYPE NumLi st I S VARRAY( 20) OF NUMBER;depts NumLi st : = NumLi st ( 10, 30, 70) ; - - depar t ment number s

    BEGI N

    . . .FOR i I N dept s. FI RST. . dept s. LAST LOOPDELETE FROM emp WHERE dept no = dept s( i ) ;

    END LOOP;END;

    In such cases, if the SQL statement affects four or more database rows, the use of bulk binds canimprove performance considerably.

    How Do Bulk Binds Improve Performance?

    The assigning of values to PL/SQL variables in SQL statements is calledbinding. PL/SQL binding

    operations fall into three categories:

    z in-bind When a PL/SQL variable or host variable is stored in the database by anI NSERT orUPDATE statement.

    z out-bindWhen a database value is assigned to a PL/SQL variable or a host variable by theRETURNI NGclause of an I NSERT, UPDATE, or DELETE statement.

    z defineWhen a database value is assigned to a PL/SQL variable or a host variable by aSELECT orFETCHstatement.

    Page 29of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    30/50

    A DML statement can transfer all the elements of a collection in a single operation, a process known asbulk binding. If the collection has 20 elements, bulk binding lets you perform the equivalent of 20SELECT, I NSERT, UPDATE, or DELETE statements using a single operation. This technique improvesperformance by minimizing the number of context switches between the PL/SQL and SQL engines. Withbulk binds, entire collections, not just individual elements, are passed back and forth.

    To do bulk binds with I NSERT, UPDATE, andDELETE statements, you enclose the SQL statement within a

    PL/SQL FORALL statement.

    To do bulk binds withSELECT statements, you include theBULKCOLLECT clause in theSELECT statementinstead of using I NTO.

    For full details of the syntax and restrictions for these statements, see "FORALL Statement" and"SELECT INTO Statement".

    Example: Performing a Bulk Bind with DELETE

    The followingDELETE statement is sent to the SQL engine just once, even though it performs threeDELETE operations:

    DECLARETYPE NumLi st I S VARRAY( 20) OF NUMBER;depts NumLi st : = NumLi st ( 10, 30, 70) ; - - depar t ment number s

    BEGI NFORALL i I N dept s. FI RST. . dept s. LAST

    DELETE FROM emp WHERE dept no = dept s( i ) ;END;

    Example: Performing a Bulk Bind with INSERT

    In the example below, 5000 part numbers and names are loaded into index-by tables. All table elements

    are inserted into a database table twice: first using aFOR loop, then using aFORALL statement. TheFORALL version is much faster.

    SQL> SET SERVEROUTPUT ONSQL> CREATE TABLE par t s ( pnumNUMBER( 4) , pname CHAR( 15)) ;

    Tabl e cr eated.

    SQL> GET test . sql1 DECLARE2 TYPE NumTab I S TABLE OF NUMBER( 4) I NDEX BY BI NARY_I NTEGER;3 TYPE NameTab I S TABLE OF CHAR( 15) I NDEX BY BI NARY_I NTEGER;4 pnums NumTab;5 pnames NameTab;

    6 t 1 NUMBER( 5) ;7 t 2 NUMBER( 5) ;8 t 3 NUMBER( 5) ;9

    1011 BEGI N12 FOR j I N 1. . 5000 LOOP - - l oad i ndex- by t abl es13 pnums( j ) : = j ;14 pnames( j ) : = ' Par t No. ' | | TO_CHAR( j ) ;15 END LOOP;16 t 1 : = dbms_uti l i t y. get _t i me;17 FOR i I N 1. . 5000 LOOP - - use FOR l oop

    Page 30of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    31/50

    18 I NSERT I NTO par t s VALUES ( pnums( i ) , pnames( i ) ) ;19 END LOOP;20 t 2 : = dbms_uti l i t y. get _t i me;21 FORALL i I N 1. . 5000 - - use FORALL st at ement22 I NSERT I NTO par t s VALUES ( pnums( i ) , pnames( i ) ) ;23 get _t i me(t 3) ;24 dbms_out put . put _l i ne( ' Execut i on Ti me ( secs) ' ) ;25 dbms_output . put_ l i ne( ' - - - - - - - - - - - - - - - - - - - - - ' ) ;26 dbms_out put . put _l i ne( ' FOR l oop: ' | | TO_CHAR( t 2 - t 1) ) ;

    27 dbms_out put . put _l i ne(' FORALL: ' | | TO_CHAR( t 3 - t 2) ) ;28* END;SQL> /Execut i on Ti me ( secs)- - - - - - - - - - - - - - - - - - - - -FOR l oop: 32FORALL: 3

    PL/ SQL procedure successf ul l y compl eted.

    Using the FORALL Statement

    The keywordFORALL instructs the PL/SQL engine to bulk-bind input collections before sending them tothe SQL engine. Although theFORALL statement contains an iteration scheme, it isnotaFOR loop. Itssyntax follows:

    FORALL i ndex I N l ower _bound. . upper_boundsql _st at ement ;

    The index can be referenced only within theFORALL statement and only as a collection subscript. TheSQL statement must be an I NSERT, UPDATE, or DELETE statement that references collection elements.And, the bounds must specify a valid range of consecutive index numbers. The SQL engine executes theSQL statement once for each index number in the range.

    Example: Using FORALL with Part of a Collection

    As the following example shows, the bounds of the FORALL loop can apply to part of a collection, notnecessarily all the elements:

    DECLARETYPE NumLi st I S VARRAY( 10) OF NUMBER;dept s NumLi st : = NumLi st ( 20, 30, 50, 55, 57, 60, 70, 75, 90, 92) ;

    BEGI NFORALL j I N 4. . 7 - - bul k- bi nd onl y par t of var r ay

    UPDATE emp SET sal = sal * 1. 10 WHERE dept no = dept s( j ) ;END;

    Example: Bulk Bind Requires Subscripted Collection

    The SQL statement can reference more than one collection. However, the PL/SQL engine bulk-bindsonly subscripted collections. So, in the following example, it does not bulk-bind the collection sal s,which is passed to the function medi an:

    FORALL i I N 1. . 20I NSERT I NTO emp2 VALUES ( enums( i ) , names( i ) , medi an( sal s) , . . . ) ;

    Page 31of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    32/50

    Example: Inserting into an Object Table with FORALL

    In addition to relational tables, theFORALL statement can manipulate object tables, as the followingexample shows:

    CREATE TYPE PNum AS OBJ ECT (n NUMBER) ;/CREATE TABLE par t no OF PNum;

    DECLARETYPE NumTab I S TABLE OF NUMBER;nums NumTab : = NumTab( 1, 2, 3, 4) ;TYPE PNumTab I S TABLE OF PNum;pnums PNumTab : = PNumTab( PNum( 1) , PNum( 2) , PNum( 3) , PNum( 4) ) ;

    BEGI NFORALL i I N pnums. FI RST. . pnums. LAST

    I NSERT I NTO par t no VALUES( pnums( i ) ) ;FORALL i I N nums. FI RST. . nums. LAST

    DELETE FROM par t no WHERE n = 2 * nums( i ) ;FORALL i I N nums. FI RST. . nums. LAST

    I NSERT I NTO part no VALUES(100 + nums( i ) ) ;END;

    How FORALL Affects Rollbacks

    In aFORALL statement, if any execution of the SQL statement raises an unhandled exception, all databasechanges made during previous executions are rolled back. However, if a raised exception is caught andhandled, changes are rolled back to an implicit savepoint marked before each execution of the SQLstatement. Changes made during previous executions arenot rolled back. For example, suppose youcreate a database table that stores department numbers and job titles, as follows:

    CREATE TABLE emp2 ( deptno NUMBER( 2) , j ob VARCHAR2( 15)) ;

    Next, you insert some rows into the table, as follows:

    I NSERT I NTO emp2 VALUES( 10, ' Cl erk' ) ;I NSERT I NTO emp2 VALUES( 10, ' Cl erk' ) ;I NSERT I NTO emp2 VALUES( 20, ' Bookkeeper' ) ; - - 10- char j ob t i t l eI NSERT I NTO emp2 VALUES( 30, ' Anal yst ' ) ;I NSERT I NTO emp2 VALUES( 30, ' Anal yst ' ) ;

    Then, you try to append the 7-character string ' ( t emp) ' to certain job titles using the followingUPDATEstatement:

    DECLARE

    TYPE NumLi st I S TABLE OF NUMBER;depts NumLi st : = NumLi st ( 10, 20, 30) ;BEGI N

    FORALL j I N dept s. FI RST. . dept s. LASTUPDATE emp2 SET j ob = j ob | | ' ( t emp) '

    WHERE dept no = dept s( j ) ;- - r ai ses a "val ue t oo l ar ge" except i on

    EXCEPTI ONWHEN OTHERS THEN

    COMMI T;END;

    Page 32of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    33/50

    The SQL engine executes theUPDATE statement three times, once for each index number in the specifiedrange, that is, once for depts( 10) , once for dept s( 20) , and once for dept s( 30) . The first executionsucceeds, but the second execution fails because the string value ' Bookkeeper ( t emp) ' is too large forthej ob column. In this case, only the second execution is rolled back.

    When any execution of the SQL statement raises an exception, theFORALL statement halts. In ourexample, the second execution of theUPDATE statement raises an exception, so the third execution is

    never done.

    Counting Rows Affected by FORALL Iterations wi th the %BULK_ROWCOUNTAttr ibute

    To process SQL data manipulation statements, the SQL engine opens an implicit cursor namedSQL. Thiscursor's scalar attributes, %FOUND, %I SOPEN, %NOTFOUND, and%ROWCOUNT, return useful information aboutthe most recently executed SQL data manipulation statement.

    TheSQL cursor has one composite attribute, %BULK_ROWCOUNT, designed for use with theFORALLstatement. This attribute has the semantics of an index-by table. Its ith element stores the number of rowsprocessed by theith execution of an I NSERT, UPDATE or DELETE statement. If theith execution affects no

    rows, %BULK_ROWCOUNT( i ) returns zero. An example follows:

    DECLARETYPE NumLi st I S TABLE OF NUMBER;depts NumLi st : = NumLi st ( 10, 20, 50) ;

    BEGI NFORALL j I N dept s. FI RST. . dept s. LAST

    UPDATE emp SET sal = sal * 1. 10 WHERE dept no = dept s( j ) ;- - Di d the 3rd UPDATE st atement af f ect any rows?

    I F SQL%BULK_ROWCOUNT( 3) = 0 THEN . . .END;

    TheFORALL statement and%BULK_ ROWCOUNT attribute use the same subscripts. For example, ifFORALLuses the range 5 .. 10, so does%BULK_ROWCOUNT.

    %BULK_ROWCOUNT is usually equal to 1 for inserts, because a typical insert operation affects only a singlerow. But for the I NSERT . . . SELECT construct, %BULK_ROWCOUNT might be greater than 1. For example,theFORALL statement below inserts an arbitrary number of rows for each iteration. After each iteration,%BULK_ROWCOUNT returns the number of items inserted:

    SET SERVEROUTPUT ON;DECLARE

    TYPE num_t ab I S TABLE OF NUMBER;dept nums num_t ab;

    BEGI N

    SELECT dept no BULK COLLECT I NTO dept nums FROM DEPT;

    FORALL i I N 1. . dept nums. COUNTI NSERT I NTO emp_by_dept

    SELECT empno, dept no FROM emp WHERE dept no =deptnums( i ) ;

    FOR i I N 1. . deptnums. COUNT LOOP- - Count how many rows were i nsert ed f or each depart ment ; t hat i s,- - how many empl oyees ar e i n each depar t ment .

    dbms_out put . put _l i ne( ' Dept ' | | dept nums( i ) | | ' : i nser t ed ' | |SQL%BULK_ROWCOUNT( i ) | | ' r ecords' ) ;

    Page 33of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    34/50

    END LOOP;

    dbms_out put . put _l i ne( ' Tot al r ecor ds i nser t ed =' | | SQL%ROWCOUNT) ;END;/

    You can also use the scalar attributes%FOUND, %NOTFOUND, and%ROWCOUNT with bulk binds. For example,

    %ROWCOUNT returns the total number of rows processed by all executions of the SQL statement.

    %FOUNDand%NOTFOUNDrefer only to the last execution of the SQL statement. However, you can use%BULK_ROWCOUNT to infer their values for individual executions. For example, when%BULK_ROWCOUNT( i ) is zero, %FOUNDand%NOTFOUNDareFALSE andTRUE, respectively.

    Handling FORALL Exceptions with the %BULK_EXCEPTIONS Attribute

    PL/SQL provides a mechanism to handle exceptions raised during the execution of aFORALL statement.This mechanism enables a bulk-bind operation to save information about exceptions and continueprocessing.

    To have a bulk bind complete despite errors, add the keywordsSAVEEXCEPTI ONS to your FORALLstatement. The syntax follows:

    FORALL i ndex I N l ower_bound. . upper _bound SAVE EXCEPTI ONS{i nser t _st mt | updat e_st mt | del et e_st mt }

    All exceptions raised during the execution are saved in the new cursor attribute%BULK_EXCEPTI ONS,which stores a collection of records. Each record has two fields. The first field, %BULK_EXCEPTI ONS( i ) . ERROR_I NDEX, holds the "iteration" of theFORALL statement during which the exception was raised.The second field, %BULK_EXCEPTI ONS( i ) . ERROR_CODE, holds the corresponding Oracle error code.

    The values stored by %BULK_EXCEPTI ONS always refer to the most recently executedFORALL statement.The number of exceptions is saved in the count attribute of%BULK_EXCEPTI ONS, that is, %BULK_EXCEPTI ONS. COUNT. Its subscripts range from 1 toCOUNT.

    If you omit the keywordsSAVEEXCEPTI ONS, execution of theFORALL statement stops when an exceptionis raised. In that case,SQL%BULK_EXCEPTI ONS. COUNT returns 1, andSQL%BULK_EXCEPTI ONS contains justone record. If no exception is raised during execution, SQL%BULK_EXCEPTI ONS. COUNT returns 0.

    The following example shows how useful the cursor attribute%BULK_EXCEPTI ONS can be:

    DECLARETYPE NumLi st I S TABLE OF NUMBER;num_t ab NumLi st : = NumLi st ( 10, 0, 11, 12, 30, 0, 20, 199, 2, 0, 9, 1) ;er r or s NUMBER;dml _er r ors EXCEPTI ON;PRAGMA except i on_i ni t ( dml _er r ors , - 24381) ;

    BEGI NFORALL i I N num_t ab. FI RST. . num_t ab. LAST SAVE EXCEPTI ONS

    DELETE FROM emp WHERE sal > 500000/ num_t ab( i ) ;EXCEPTI ON

    WHEN dml _er r or s THENer r or s : = SQL%BULK_EXCEPTI ONS. COUNT;dbms_out put . put _l i ne( ' Number of er r or s i s ' | | er r or s) ;FOR i I N 1. . er r ors LOOP

    dbms_out put . put _l i ne( ' Err or ' | | i | | ' occurr ed dur i ng ' | |

    Page 34of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    35/50

    ' i t erat i on ' | | SQL%BULK_EXCEPTI ONS( i ) . ERROR_I NDEX) ;dbms_out put . put _l i ne( ' Oracl e err or i s ' | |

    SQLERRM( - SQL%BULK_EXCEPTI ONS( i ) . ERROR_CODE) ) ;END LOOP;

    END;

    In this example, PL/SQL raised the predefined exceptionZERO_DI VI DE when i equaled 2, 6, 10. After

    the bulk-bind completed, SQL%BULK_EXCEPTI ONS. COUNT returned 3, and the contents ofSQL%BULK_EXCEPTI ONS were (2,1476), (6,1476), and (10,1476). To get the Oracle error message (whichincludes the code), we negated the value ofSQL%BULK_EXCEPTI ONS( i ) . ERROR_CODE and passed theresult to the error-reporting function SQLERRM, which expects a negative number. Here is the output:

    Number of err ors i s 3Er r or 1 occur r ed dur i ng i t er at i on 2Or acl e er r or i s ORA- 01476: di vi sor i s equal t o zer oEr r or 2 occur r ed dur i ng i t er at i on 6Or acl e er r or i s ORA- 01476: di vi sor i s equal t o zer oEr r or 3 occur r ed dur i ng i t er at i on 10Or acl e er r or i s ORA- 01476: di vi sor i s equal t o zer o

    Retrieving Query Results into Collections with the BULKCOLLECT Clause

    The keywordsBULKCOLLECT tell the SQL engine to bulk-bind output collections before returning themto the PL/SQL engine. You can use these keywords in theSELECTI NTO, FETCHI NTO, andRETURNI NGI NTOclauses. Here is the syntax:

    . . . BULK COLLECT I NTO col l ect i on_name[ , col l ect i on_name] . . .

    The SQL engine bulk-binds all collections referenced in theI NTOlist. The corresponding columns canstore scalar or composite values including objects. In the following example, the SQL engine loads theentireempno andename database columns into nested tables before returning the tables to the PL/SQLengine:

    DECLARETYPE NumTab I S TABLE OF emp. empno%TYPE;TYPE NameTab I S TABLE OF emp. ename%TYPE;enums NumTab; - - no need t o i ni t i al i zenames NameTab;

    BEGI NSELECT empno, ename BULK COLLECT I NTO enums, names FROM emp;. . .

    END;

    In the next example, the SQL engine loads all the values in an object column into a nested table beforereturning the table to the PL/SQL engine:

    CREATE TYPE Coor ds AS OBJ ECT (x NUMBER, y NUMBER) ;CREATE TABLE gr i d ( num NUMBER, l oc Coords) ;I NSERT I NTO gr i d VALUES( 10, Coor ds( 1, 2)) ;I NSERT I NTO gr i d VALUES( 20, Coor ds( 3, 4)) ;

    DECLARE

    Page 35of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    36/50

    TYPE CoordsTab I S TABLE OF Coor ds;pai r s Coor dsTab;

    BEGI NSELECT l oc BULK COLLECT I NTO pai r s FROM gr i d;- - now pai r s cont ai ns ( 1, 2) and ( 3, 4)

    END;

    The SQL engine initializes and extends collections for you. (However, it cannot extend varrays beyondtheir maximum size.) Then, starting at index 1, it inserts elements consecutively and overwrites any pre-existent elements.

    The SQL engine bulk-binds entire database columns. So, if a table has 50,000 rows, the engine loads50,000 column values into the target collection. However, you can use the pseudocolumn ROWNUMto limitthe number of rows processed. In the following example, you limit the number of rows to 100:

    DECLARETYPE Sal Li st I S TABLE OF emp. sal %TYPE;sal s Sal Li st ;

    BEGI NSELECT sal BULK COLLECT I NTO sal s FROM emp

    WHERE ROWNUM 1000;names NameLi st ;sal s Sal Li st ;

    BEGI NOPEN c1;FETCH c1 BULK COLLECT I NTO names, sal s;

    END;

    Into a Collection of Records

    You can bulk-fetch from a cursor into a collection of records:

    DECLARETYPE DeptRecTab I S TABLE OF dept %ROWTYPE;dept _r ecs Dept RecTab;CURSOR c1 I S

    SELECT deptno, dname, l oc FROM dept WHERE deptno > 10;BEGI N

    OPEN c1;FETCH c1 BULK COLLECT I NTO dept _r ecs;

    END;

    Limi ting the Rows for a Bulk FETCH Operation wi th the LIMIT Clause

    Page 36of 50PL/SQL Collections and Records

    29/01/2010http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96624/05_colls.htm

  • 7/28/2019 PL-SQL Collections and Records

    37/50

    The optional LI MI T clause, allowed only in bulk (not scalar) FETCHstatements, lets you limit the numberof rows fetched from the database. The syntax is

    FETCH . . . BULK COLLECT I NTO . . . [ LI MI T rows] ;

    wherer ows can be a literal, variable, or expression but must evaluate to a number. Otherwise, PL/SQLraises the predefined exceptionVALUE_ERROR. I f the number is not positive, PL/SQL raisesI NVALI D_NUMBER. If necessary, PL/SQL rounds the number to the nearest integer.

    In the example below, with each iteration of the loop, theFETCHstatement fetches ten rows (or less) intoindex-by tableempnos . The previous values are overwritten.

    DECLARETYPE NumTab I S TABLE OF NUMBER I NDEX BY BI NARY_I NTEGER;CURSOR c1 I S SELECT empno FROM emp;empnos NumTab;r ows NATURAL : = 10;

    BEGI NOPEN c1;LOOP

    / * The f ol l owi ng stat ement f et ches 10 r ows ( or l ess) . */FETCH c1 BULK COLLECT I NTO empnos LI MI T r ows;EXI T WHEN c1%NOTFOUND;. . .

    END LOOP;CLOSE c1;

    END;

    Retrieving DML Results into a Collection with the RETURNING INTO Clause

    You can use theBULKCOLLECT clause in theRETURNI NGI NTOclause of an I NSERT, UPDATE, or DELETEstatement, as the following example shows:

    DECLARETYPE NumLi st I S TABLE OF emp. empno%TYPE;enums NumLi st ;

    BEGI NDELETE FROM emp WHERE dept no = 20

    RETURNI NG empno BULK COLLECT I NTO enums;- - i f t her e were f i ve empl oyees i n depart ment 20,- - t hen enums cont ai ns f i ve empl oyee number s

    END;

    Restrictions on BULK COLLECT

    The following restrictions apply to theBULKCOLLECT clause:

    z You cannot bulk collect into an associative array that has a string type for the key.

    z You can use theBULKCOLLECT clause only in server-side programs (not in client-side programs).Otherwise, you get the error this feature is not supported in client-side programs.