Successfully reported this slideshow.
Your SlideShare is downloading. ×

All About PL/SQL Collections

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 92 Ad

All About PL/SQL Collections

Download to read offline

Collections are PL/SQL's approach to arrays. We have three types of collections (associative arrays, nested tables, varrays) and this presentation explores both the common features of these datatypes, and their differing characteristics. Copyright 2016 Oracle Corporation.

Collections are PL/SQL's approach to arrays. We have three types of collections (associative arrays, nested tables, varrays) and this presentation explores both the common features of these datatypes, and their differing characteristics. Copyright 2016 Oracle Corporation.

Advertisement
Advertisement

More Related Content

Slideshows for you (20)

Similar to All About PL/SQL Collections (20)

Advertisement
Advertisement

All About PL/SQL Collections

  1. 1. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | All About PL/SQL Collections 1 Steven Feuerstein Oracle Developer Advocate for PL/SQL Oracle CorporaDon Email: steven.feuerstein@oracle.com TwiLer: @sfonplsql Blog: stevenfeuersteinonplsql.blogspot.com YouTube: PracDcally Perfect PL/SQL
  2. 2. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 2 Resources for Oracle Database Developers •  Official home of PL/SQL - oracle.com/plsql •  SQL-PL/SQL discussion forum on OTN hLps://community.oracle.com/community/database/developer-tools/sql_and_pl_sql •  PL/SQL and EBR blog by Bryn Llewellyn - hLps://blogs.oracle.com/plsql-and-ebr •  Oracle Learning Library - oracle.com/oll •  Weekly PL/SQL and SQL quizzes, and more - plsqlchallenge.oracle.com •  Ask Tom - asktom.oracle.com – 'nuff said •  LiveSQL - livesql.oracle.com – script repository and 12/7 12c database •  oracle-developer.net - great content from Adrian Billington •  oracle-base.com - great content from Tim Hall
  3. 3. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 3 Agenda •  IntroducDon and overview •  Defining and using collecDon types •  Using collecDon methods •  Working with associaDve arrays •  Working with nested tables •  Working with varrays •  Using collecDons inside SQL •  Benefits of Non-SequenDal Indexing •  Using String Indexes with AssociaDve Arrays •  Working with Nested CollecDons •  Using MULTISET Operators with Nested Tables •  Best PracDces for CollecDons
  4. 4. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 4 PL/SQL Collec>ons •  A collecDon is an "ordered group of elements, all of the same type." (PL/SQL User Guide) – In short, a "homogeneous" list of "stuff" •  CollecDons are similar to single-dimensional arrays in other programming languages. – With lots of subtle differences, as well. •  CollecDons almost always consume Process Global Area memory. •  CollecDons should be a "go to" datatype for Oracle Database developers 1 Apple 22 Pear 100 Orange 10023 Apricot
  5. 5. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 5 System Global Area (SGA) of RDBMS Instance PL/SQL in Shared Memory Shared Pool Large Pool Reserved Pool show_emps calc_totals upd_salaries Select * from emp Shared SQL Pre-parsed Update emp Set sal=... Library cache Session 1 memory (PGA/UGA) emp_rec emp%rowtype; tot_tab tottabtype; Session 2 memory (PGA/UGA) emp_rec emp%rowtype; tot_tab tottabtype;Session 1 Session 2
  6. 6. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 6 How PL/SQL uses the SGA, PGA and UGA • The SGA contains informaDon that can be shared across sessions connected to the instance. – In PL/SQL, this is limited to package staDc constants. • The User Global Area contains session-specific data that persists across server call boundaries – Package-level data • The Process Global Area contains session-specific data that is released when the current server call terminates: "local" data. PACKAGE Pkg is   Nonstatic_Constant CONSTANT PLS_INTEGER := My_Sequence.Nextval;   Static_Constant    CONSTANT PLS_INTEGER := 42; END Pkg;
  7. 7. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 7 Calcula>ng PGA and UGA Consump>on • Oracle keeps track of and shows the PGA and UGA consumpDon for a session in the v_$sesstat dynamic view. • With the correct privileges, PL/SQL developers can analysis their code's memory usage. show_pga_uga.sql grantv$.sql plsql_memory.pkg plsql_memory_demo.sql SELECT n.name, s.VALUE FROM sys.v_$sesstat s, sys.v_$statname n WHERE s.statistic# = n.statistic# AND s.sid = my_session.sid AND n.name IN ('session uga memory', 'session pga memory') BEGIN plsql_memory.start_analysis; run_my_application; plsql_memory.show_memory_usage; END;
  8. 8. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 8 Why use collec>ons? • Generally, to manipulate lists of informaDon in memory. – Of course, you can use relaDonal tables, too. – CollecDon manipulaDon is generally much faster than using SQL to modify the contents of tables. • CollecDons enable other key features of PL/SQL – BULK COLLECT and FORALL use them to boost mulD-row SQL performance – Serve up complex datasets of informaDon to non-PL/SQL host environments using table func/ons.
  9. 9. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 9 Different Types of Collec>ons • Three types of collecDons – AssociaDve array – Nested table – Varray (varying arrays) • AssociaDve array is a PL/SQL-only datatype. • Nested tables and varrays can be used within PL/SQL blocks and also from within SQL. – Column tables – Table funcDons
  10. 10. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 10 Glossary of Terms •  Element – A collection is made up of one or more elements, all of the same type. Also referred to as "row." – Can be of almost any valid PL/SQL type. •  Index value – The "location" in the collection in which an element is found. Also referred to as "row number." – Usually an integer, can also be a string (associative arrays only) •  Dense – Every index value between lowest and highest has a defined element. •  Sparse – One or more elements between lowest and highest index values may be undefined (gaps).
  11. 11. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 11 Defining collec>on types • Before you can manipulate a collecDon variable, you need a collecDon type on which to declare the variable. • Oracle pre-defines several collecDon types in various supplied packages. • DBMS_SQL – Dynamic SQL-specific types – Generic types (list of strings, numbers, etc.). • DBMS_OUTPUT – List of strings
  12. 12. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 12 Defining collec>on types • Declare all collecDon type with a TYPE statement. • AssociaDve arrays use IS TABLE OF and the INDEX BY clause. • Nested tables use IS TABLE OF, without any indexing clause. • Varrays use IS VARRAY OF syntax. TYPE coll_name IS TABLE OF element_type INDEX BY index_type; TYPE coll_name IS TABLE OF element_type; TYPE coll_name IS VARRAY (limit) OF element_type; Associa>on array type Nested table type Varray type
  13. 13. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 13 Scope for Collec>on Types • You can define collecDon types in: – Local block – can be used only in that block – Package - available for use by any session with execute authority on that package – Schema – in the SQL layer, possible only for nested tables and varrays • Avoid "reinvenDng" collecDon types in many places in your code. – They are excellent candidates for shared code elements.
  14. 14. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 14 Local collec>on types • TYPE statement found in declaraDon secDon of block (anonymous, nested, subprogram) • It is defined and then destroyed each Dme the block is executed. • You should avoid local types; it will likely lead to redundancies in your code. DECLARE TYPE strings_t IS TABLE OF VARCHAR2(100); PROCEDURE my_procedure IS TYPE strings_t IS TABLE OF VARCHAR2(100);
  15. 15. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 15 Package-level Types • When defined in the package specificaDon, it becomes a "globally" available type. – Any session with EXECUTE authority on the package can use the type to declare collecDons. • In the package body, can only be used by subprograms of that package. • Excellent repository for applicaDon-specific types PACKAGE my_types IS TYPE strings_t IS TABLE OF VARCHAR2(100); colltypes.pks
  16. 16. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 16 Schema-level Types • Defined in the schema, independent of any PL/SQL program unit. • Any session with EXECUTE authority on type can use it to declare collecDon variables. – CollecDons of this type can also be directly referenced inside SQL statements. • Can only be used with nested tables and varrays. – AssociaDve arrays are PL/SQL-specific, cannot be defined at the schema level (SQL layer). CREATE OR REPLACE TYPE strings_t IS TABLE OF VARCHAR2(100) GRANT EXECUTE ON strings_t TO PUBLIC
  17. 17. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 17 Declaring collec>on variables • Once you have defined your collecDon type, you can define a variable based on that. – The same as for any type of data in PL/SQL CREATE TYPE hire_dates_t IS TABLE OF DATE; CREATE PACKAGE my_types IS TYPE strings_t IS TABLE OF VARCHAR2(100); END my_types; DECLARE l_names my_types.string_t; l_dates hire_dates_t; l_dates HR.hire_dates_t; l_strings DBMS_SQL.varchar2_table;
  18. 18. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 18 Collec>on Methods • The term method is used to describe procedures and funcDons that defined in a class or object type. – You invoke a method by aLaching it, using dot notaDon, to the name of the type/ class or to an instance of the class. • CollecDon methods are procedures and funcDons that are a6ached to a collecDon variable. – First introducDon of object-oriented syntax in PL/SQL – way back in Oracle 7.3.4! method_vs_proc.sql
  19. 19. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 19 Methods that retrieve informa>on • COUNT: number of elements currently defined in collecDon. • EXISTS: TRUE if the specified index values is defined. • FIRST/LAST: lowest/highest index values of defined rows. • NEXT/PRIOR: defined index value ater/before the specified index value . • LIMIT: max. number of elements allowed in a VARRAY.
  20. 20. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 20 The COUNT Method • Returns 0 if the collecDon is empty. • Otherwise returns the number of defined index values. • You cannot ask for a count of elements between a range of index values. Too bad... BEGIN IF my_collection.COUNT > 0 THEN /* We have some data in the collection */ ... END IF;
  21. 21. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 21 Checking for element existence • If you try to read an element at an undefined index value, Oracle raises the NO_DATA_FOUND excepDon. – A poor decision on Oracle's part. • Use the EXISTS method to check to see if the index value is defined. BEGIN IF my_collection.EXISTS (l_index) THEN DBMS_OUTPUT.PUT_LINE (my_collection (l_index)); END IF; collection_exists.sql plsqlloops.sp
  22. 22. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 22 Naviga>ng Through Collec>ons • One of the most common acDons on collecDons is looping through the contents. • You can use WHILE, simple and FOR loops to perform this navigaDon. • The characterisDcs of your collecDon will determine which sort of loop to use.
  23. 23. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 23 Choose the Right Loop • FOR loop – Only use this loop when you want to iterate through every element between the low and high index values. – Do not use with sparse collecDons. • WHILE and simple loops – Best fit for sparse collecDons and when you want to condi/onally exit from your loop.
  24. 24. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 24 Naviga>on methods and FOR loops • With FOR loops, you will use: – COUNT – when the first index value in the collecDon is 1. – FIRST and LAST when FIRST may not be one. BEGIN FOR indx IN 1 .. my_collection.COUNT LOOP do_something_with (my_collection (indx)); END LOOP; END; BEGIN FOR indx IN my_collection.FIRST .. my_collection.LAST LOOP do_something_with (my_collection (indx)); END LOOP; END; plsqlloops.sp
  25. 25. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 25 Naviga>on methods & WHILE/simple loops • With WHILE and simple loops, you will use – FIRST and NEXT to move from first to last – LAST and PRIOR to move from last to first rowind PLS_INTEGER := my_collection.FIRST; BEGIN LOOP EXIT WHEN rowind IS NULL; rowind := my_collection.NEXT (rowind); END LOOP; END; rowind PLS_INTEGER := my_collection.LAST; BEGIN LOOP EXIT WHEN rowind IS NULL; rowind := my_collection.PRIOR (rowind); END LOOP; END; plsqlloops.sp
  26. 26. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 26 The LIMIT Method • Only the varray has a pre-defined upper limit on the number of elements that can defined in it. – Well, the other collecDons types theore/cally have an upper limit, but you'll never reach it. • Use the LIMIT method to determine what that limit is. DECLARE TYPE max_of_five_t IS VARRAY (5) OF NUMBER; l_list max_of_five_t := max_of_five_t(); BEGIN DBMS_OUTPUT.put_line (l_list.LIMIT); END; varray_limit.sql
  27. 27. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 27 Methods that change a collec>on • DELETE deletes one or more rows from an associaDve array or nested table. • EXTEND adds rows to the end of a nested table or varray. • TRIM removes rows from a varray or nested table.
  28. 28. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 28 The DELETE Method • You can delete one or more rows from an associaDve array or nested table using DELETE. • Try to DELETE from a varray and you will see "PLS-00306: wrong number or types of arguments in call to 'DELETE'" • Low and high index values do not have to exist. BEGIN -- Delete all rows myCollection.DELETE; -- Delete one (the last) row myCollection.DELETE (myCollection.LAST); -- Delete a range of rows myCollection.DELETE (1400, 17255); END; delete.sql
  29. 29. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 29 Make room for new elements w/ EXTEND • Use EXTEND only with varrays and nested tables. • Tell Oracle to add N number of new elements to the end of the collecDon. • "Bulk" extends faster than individual extends. – If you know you will need 10,000 elements, do the extend in a single step. • OpDonal: specify the value of all new elements from an exisDng element. – Default value is NULL. extend.sql
  30. 30. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 30 Trimming elements from end of collec>on • Use TRIM only with varrays and nested tables. – Not to be confused with the TRIM funcDon! • You can trim one or mulDple elements. – Default is 1. – "ORA-06533: Subscript beyond count" error if you to trim more than is in the collecDon. • TRIM is the only way to remove elements from a varray. – DELETE is not supported. trim.sql
  31. 31. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 31 Conclusions – Collec>on Methods • Methods make it much easier to work with collecDons. • You can get informaDon about the collecDons and also change their contents. • When you use the navigaDon methods, make sure you choose the appropriate type of loop to iterate through the elements.
  32. 32. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 32 Associa>ve Arrays •  A variable declared from an associaDve array type. •  An unbounded set of key-value pairs. •  Each key is unique, and serves as the subscript of the element that holds the corresponding value. •  You can access elements without knowing their posiDons in the array, and without traversing the array. 1 Apple 22 Pear 100 Orange 10023 Apricot DECLARE TYPE list_of_names_t IS TABLE OF employees.last_name%TYPE INDEX BY PLS_INTEGER;
  33. 33. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 33 Associa>ve Array Background • It was the first type of collecDon available in PL/SQL. • First introduced in Oracle7 as a "PL/SQL table" (hence, the TABLE OF syntax). • Renamed in Oracle8 to "index-by table" when nested tables and varrays were added. • In 9.2, renamed to "associaDve array" with the advent of string indexing. • Can only be used in a PL/SQL context.
  34. 34. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 34 Characteris>cs of Associa>ve Arrays • TABLE OF datatypes can be almost any valid PL/SQL type (details to follow). • INDEX BY type can be integer or string. – This means you can essenDally index by anything! – But index values can never be NULL. • AssociaDve arrays can be sparse. – Can populate elements in non-consecu/ve index values. – Easily used to emulate primary keys and unique indexes. DECLARE TYPE list_of_names_t IS TABLE OF employees.last_name%TYPE INDEX BY PLS_INTEGER;
  35. 35. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 35 Simple associa>ve array example DECLARE TYPE list_of_names_t IS TABLE OF VARCHAR2 (20) INDEX BY PLS_INTEGER; happyfamily list_of_names_t; l_index_value PLS_INTEGER := 88; BEGIN happyfamily (1) := 'Eli'; happyfamily (-15070) := 'Steven'; happyfamily (3) := 'Chris'; happyfamily (l_index_value) := 'Veva'; l_index_value := happyfamily.FIRST; WHILE (l_index_value IS NOT NULL) LOOP DBMS_OUTPUT.put_line ( 'Value at index ' || l_index_value || ' = ' || happyfamily (l_index_value) ); l_index_value := happyfamily.NEXT (l_index_value); END LOOP; END; assoc_array_example.sql
  36. 36. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 36 Associa>ve array of records example • It is very easy to "emulate" a relaDonal table inside one's PL/SQL code. – Or use any other kind of record type. DECLARE TYPE employees_aat IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER; l_employees employees_aat; BEGIN FOR employee_rec IN (SELECT * FROM employees) LOOP l_employees (l_employees.COUNT + 1) := employee_rec; END LOOP; END; collection_of_records.sql
  37. 37. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 37 Valid TABLE OF datatypes • You can create an associaDve array of almost any PL/SQL or SQL datatype. – All scalar types, including Boolean – CollecDon of object types – CollecDon of other collecDons • There are some restricDons: – Cannot have a TABLE OF cursor variables or excepDons. aa_table_of_invalid_types.sql
  38. 38. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 38 Valid Index Values • No prac/cal limit to number of elements you can define in an associaDve array. • Integer index values range from -2,147,483,647 to 2,147,483,647 – This is the BINARY_INTEGER range. – That's almost 4.3 billion elements! • String index values can have any value; you are only restricted by maximum number of elements allowed in a collecDon. – Which you will never reach. aa_limits.sql
  39. 39. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 39 More details on valid INDEX BY types • The INDEX BY clause defines the indexing for the collecDon. • You can define the index datatype of your associaDve array type to be: – BINARY_INTEGER and any sub-type derived from BINARY_INTEGER – VARCHAR2(n), where n is between 1 and 32767 – %TYPE against a database column that is consistent with the above rules – A SUBTYPE against any of the above. indexby_options.sql
  40. 40. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 40 Nested Tables and Varrays • Added in Oracle8 as part of the object model. • Types can be defined in PL/SQL or a schema-level type. • You must ini/alize before using the collecDon. – There are some excepDons, as with BULK COLLECT. • You must extend to make room for new elements. – There are some excepDons, as with BULK COLLECT. • Columns in relaDonal tables can be of type nested table or varray. – Oh, but the denormalizaDon!
  41. 41. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 41 Nested Tables •  A nested table is a type of collecDon, which, according to Oracle documentaDon, "models an unordered set of elements." – It is a "mulDset": like a relaDonal table, there is no inherent order to its elements, and duplicates are allowed/ significant. •  From a pracDcal standpoint, you can access nested table elements through an integer index. •  MULTISET operators allow set-level operaDons on nested tables. 1 Apple 2 Pear 3 Orange 4 Apricot CREATE OR REPLACE TYPE list_of_names_t IS TABLE OF NUMBER; 5 Pear Unordered set of elements Integer index also available nested_table_example.sql
  42. 42. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 42 Varrays • A varray (short for "variable size array) is a type of collecDon that has an upper bound on its number of elements. • This upper limit is set when the type is defined, but can also be adjusted at runDme. • Always dense, can only trim from end of varray. • Other than that, quite similar to a nested table. 1 Apple 2 Pear 3 Orange 4 Apricot CREATE OR REPLACE TYPE list_of_names_t IS VARRAY (5) OF NUMBER; 5 Pear And no more elements can fit in this varray. varray_example.sql
  43. 43. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 43 Ini>alizing Nested Tables and Varrays • Before you can use a nested table, it must be iniDalized. – IniDalize them explicitly with a constructor funcDon, same name as type, provided by Oracle – Provide a list of values or iniDalize it as empty. DECLARE TYPE numbers_t IS VARRAY (5) OF NUMBER; salaries numbers_t := numbers_t (100, 200, 300); BEGIN DECLARE TYPE numbers_t IS TABLE OF NUMBER; salaries numbers_t; BEGIN salaries := numbers_t (100, 200, 300); Initialize in execution section Initialize in declaration with values DECLARE TYPE numbers_t IS TABLE OF NUMBER; salaries numbers_t := numbers_t (); Initialize empty in declaration
  44. 44. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 44 Valid TABLE OF and VARRAY datatypes • For PL/SQL-defined types, you can create nested table of almost any PL/ SQL or SQL datatype. – All scalar types, including Boolean; collecDon of object types; collecDon of other collecDons • There are some restricDons: – Cannot have a TABLE OF or VARRAY OF cursor variables or excepDons. • Schema-level types can only use SQL datatypes. nt_table_of_invalid_types.sql va_table_of_invalid_types.sql
  45. 45. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 45 Collec>on as Column Type • If the type is defined at schema level, it can be used as a column type. – Must also provide a STORE AS clause. • The order of elements in the column is not preserved. • Can specify storage characterisDcs of collecDon. • See separate lesson for details on using collecDons in SQL. CREATE TABLE family ( surname VARCHAR2 (1000) , parent_names parent_names_t , children_names child_names_t ) NESTED TABLE children_names STORE AS parent_names_tbl [storage_clause] NESTED TABLE parent_names STORE AS children_names_tbl [storage_clause] nested_table_example.sql varray_example.sql
  46. 46. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 46 Changing Upper Limit on Varray • You specify an upper limit at the Dme the varray type is define. • You can also change this limit at runDme with an ALTER TYPE command. ALTER TYPE my_varray_t MODIFY LIMIT 100 INVALIDATE / BEGIN EXECUTE IMMEDIATE 'ALTER TYPE my_varray_t MODIFY LIMIT 100 CASCADE'; END; / varray_change_limit.sql
  47. 47. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 47 Using Collec>ons Inside SQL • Define your collecDon type at the schema level & collecDons declared with that type can be referenced in the SQL layer. – As a column in a relaDonal table – By selecDng from that collecDon in a SELECT statement (note: as of 12.1, you can do this with associaDve arrays indexed by integer). • Oracle offers ways to "translate" between a collecDon format and a relaDonal table format. – TABLE: collecDon -> relaDonal table – MULTISET: relaDonal table -> collecDon
  48. 48. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 48 Using the TABLE Operator • Use TABLE to work with data in a collecDon as if it were data in a database table. – Oracle refers to this as "un-nesDng". – Especially useful when you would like to apply SQL operaDons to a PL/ SQL collecDon (ie, one not stored in a database table). • You do not need to explicitly CAST the collecDon. – Oracle will figure out the type automaDcally. collections_in_sql.sql
  49. 49. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 49 Changing collec>on contents with TABLE • You can use TABLE to query the contents of a collecDon inside SQL. • You can also change the contents of a nested table column value with TABLE. – But varrays have to be changed "en masse" – the while varray is replace; cannot modify individual elements. UPDATE TABLE (SELECT children_names FROM family WHERE surname = 'Feuerstein') SET COLUMN_VALUE = 'Eli Silva' WHERE COLUMN_VALUE = 'Eli' / nested_table_change.sql
  50. 50. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 50 Using the MULTISET Operator • MULTISET is the inverse of TABLE, converDng a set of table, view, query) into a VARRAY or nested table. – Use MULTISET to emulate or transform relaDonal joins into collecDons, with potenDal client-server performance impact. DECLARE CURSOR bird_curs IS SELECT b.genus, b.species, CAST ( MULTISET (SELECT bh.country FROM bird_habitats bh WHERE bh.genus = b.genus AND bh.species = b.species) AS country_tab_t) FROM birds b; bird_row bird_curs%ROWTYPE; BEGIN OPEN bird_curs; FETCH bird_curs into bird_row; END; collections_in_sql_multiset.sql
  51. 51. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 51 Non-Sequen>al Indexing • SomeDmes you simply want to add items to the end of a list. – This makes sense if the order in which items were added is significant. • But how do you find a specific element in the list? – With sequenDal indexing, you have to scan through the contents to find a match. • And what if you want to find elements in a collecDon using more than one "index"? – CollecDons have just one index. Period. string_tracker0.*
  52. 52. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 52 Taking advantage of non-sequen>al indexing • AssociaDve arrays can be sparse. – Certainly, any string-indexed collecDon is not sequenDally filled. • Valid index values for an associaDve array cover a very wide range of integers. – Very oten primary keys of tables are sequence-generated integers that fall within this range. • Combine these two features and you have a powerful and relaDvely simple mechanism for emulaDng relaDonal table keys. collection_of_records.sql
  53. 53. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 53 Emula>ng Primary Key in Collec>on • Many tables rely on sequence-generated integer values for their primary keys. – It is possible that this sequence value could exceed 2**31-1, but it is rarely the case. • Primary keys generally are not "densely" allocated. – Sequences are allocated in groups, rows are deleted. • These scenarios mesh perfectly with the features of an integer-indexed associaDve array. emulate_primary_key1.sql emulate_primary_key2.sql
  54. 54. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 54 "Mul>ple Indexes" on a Collec>on • Most relaDonal tables have mulDple indexes defined in order to opDmize query performance (for various WHERE clauses). • What if I need to do the same thing in a collecDon? • You can only have a single index on an associaDve array (INDEX BY...). – But you could create other collecDons that serve as indexes into the "original" collecDon. emulate_indexes.sql genaa.sql
  55. 55. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 55 Lots of ways to index associa>ve arrays • Prior to Oracle9i Release 2, you could only index by BINARY_INTEGER. • You can now define the index on your associaDve array to be: – Any sub-type derived from BINARY_INTEGER – VARCHAR2(n), where n is between 1 and 32767 – %TYPE against a database column that is consistent with the above rules – A SUBTYPE against any of the above. • This means that you can now index on string values! (and concatenated indexes and...)
  56. 56. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 56 Examples of New TYPE Variants • All of the following are valid TYPE declaraDons in Oracle9i Release 2 and higher – You cannot use %TYPE against an INTEGER column, because INTEGER is not a subtype of BINARY_INTEGER. DECLARE TYPE array_t1 IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; TYPE array_t2 IS TABLE OF NUMBER INDEX BY PLS_INTEGER; TYPE array_t3 IS TABLE OF NUMBER INDEX BY POSITIVE; TYPE array_t4 IS TABLE OF NUMBER INDEX BY NATURAL; TYPE array_t5 IS TABLE OF NUMBER INDEX BY VARCHAR2(64); TYPE array_t6 IS TABLE OF NUMBER INDEX BY VARCHAR2(32767); TYPE array_t7 IS TABLE OF NUMBER INDEX BY employee.last_name%TYPE; TYPE array_t8 IS TABLE OF NUMBER INDEX BY types_pkg.subtype_t;
  57. 57. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 57 Working with string-indexed collec>ons • The syntax for using string indexing is the same. – And all the same methods are available. • But the type of data returned by FIRST, LAST, NEXT and PRIOR methods is VARCHAR2. • The longer the string values, the more Dme it takes Oracle to "hash" or convert that string to the integer that is actually used as the index value. – RelaDvely small strings, say under 100 characters, do not incur too large a penalty. assoc_array*.sql assoc_array_perf.tst
  58. 58. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 58 An example of string indexing • I generate test code and declare variables. So I need to make sure that I do not declare the same variable more than once. •  There are lots of ways to do this, but string-indexed collecDons make it really easy! FOR indx IN 1 .. l_variables.COUNT LOOP If varname_already_used THEN -- DO NOTHING ELSE add_variable_declaration; mark_varname_as_used; END IF; END LOOP; string_tracker0.*
  59. 59. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 59 String Tracker without string indexing • Two subprograms are needed.... – string_in_use: returns TRUE if the string was previously used. – mark_as_used: mark the specified string as being used. • Most "obvious" implementaDon: add each string to a list of used strings. • Then search through the list for a match. string_tracker0.*
  60. 60. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 60 String Tracker with string indexing • Rather than add each string to a list of used strings, why not use the string as the index? CREATE OR REPLACE PACKAGE BODY string_tracker IS TYPE used_aat IS TABLE OF BOOLEAN INDEX BY VARCHAR2(32767); g_names_used used_aat; FUNCTION string_in_use ( value_in IN VARCHAR2 ) RETURN BOOLEAN IS BEGIN RETURN g_names_used.EXISTS ( value_in ); END string_in_use; PROCEDURE mark_as_used (value_in IN VARCHAR2) IS BEGIN g_names_used ( value_in ) := TRUE; END mark_as_used; END string_tracker; string_tracker1.*
  61. 61. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 61 Conver>ng from Integer to String Indexing • Suppose I am emulaDng my primary key in a collecDon index for a batch job. – Much beLer performance! – But my primary key values are approaching 2**31-1 (the maximum allowed in an collecDon). • Must I abandon the collecDon technique? • No! You can convert to a string index. – Now the only limitaDon is the number of elements defined in the collecDon. – You are much more likely to run out of memory before you get anywhere near 2**31-1 elements. emulate_primary_key.sql int_to_string_indexing.sql
  62. 62. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 62 Mul>level (a.k.a., Nested) Collec>ons • A mulDlevel collecDon type is a type whose element is, directly or indirectly, another collecDon. • Usages for mulDlevel collecDons: – Model normalized data structures in PL/SQL collecDons – Emulate mulDdimensional arrays. • The syntax for working with mulDlevel collecDons can be hard to parse (in your head). multilevel_collections.sql
  63. 63. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 63 String Tracker Version 2 • I introduced the string_tracker package in "Working with String-Indexed CollecDons." – Keeps track of the names of variables already generated in test code. – That worked fine for a single list. What if I need to keep track of mulDple lists, and lists within lists? • Let's extend the first version to support mulDple lists by using a string- indexed, mulD-level collecDon. A list of lists.... string_tracker1.* string_tracker2.* string_tracker3*.* List 1: 1-10000 List 2: 10001-20000 List 2: 20001-30000 The hard way: segmenDng one big collecDon
  64. 64. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 64 Emulate mul>dimensional arrays • CollecDons are always single dimensioned. • But a collecDon of collecDons is "kinda like" a two-dimensional array. – You can extrapolate from there. CREATE OR REPLACE PACKAGE multdim IS TYPE dim1_t IS TABLE OF VARCHAR2 (32767) INDEX BY PLS_INTEGER; TYPE dim2_t IS TABLE OF dim1_t INDEX BY PLS_INTEGER; TYPE dim3_t IS TABLE OF dim2_t INDEX BY PLS_INTEGER; multdim*.*
  65. 65. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 65 Complex example: four-levels of nes>ng • The most complicated structure I ever built was a four-level nested collecDon structure. • I used it to build a uDlity to analyze packages for potenDally ambiguous overloading. • The next several slides explore the implementaDon. – It is too complex to fully explain in this lesson.
  66. 66. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 66 Mul>level collec>ons as a kind of normalized database design • I have found that coming up with the right model of mulDlevel collecDons is very similar to normalizing data in relaDonal tables. – Avoid redundancy – Accurately reflect relaDonships – Simply resulDng applicaDon code • Let's take a look at an example of such a process.
  67. 67. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 67 The problem of ambiguous overloading • Oddly and sadly, it is possible to compile overloadings which are not usable. – You see an obvious example below, but there are many more subtle circumstances, usually involving defaulted parameters. • So I will build a uDlity to idenDfy such ambiguous overloadings. But how can I do this? BEGIN salespkg.calc_total ('ABC'); END; PACKAGE salespkg IS PROCEDURE calc_total ( dept_in IN VARCHAR2); PROCEDURE calc_total ( dept_in IN CHAR); END salespkg; ? ambig_overloading.sql
  68. 68. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 68 ALL_ARGUMENTS to the rescue! • Parsing is too complicated for me, but the ALL_ARGUMENTS data dicDonary view contains informaDon about all the arguments of all the procedures and funcDons to which I have access. – That sounds preLy good! • As usual, Oracle offers us a whole lot of pleasure, mixed with a liLle bit of pain. – The organizaDon of data in ALL_ARGUMENTS is a bit bizarre, plus it is incomplete, necessitaDng the use also of DBMS_DESCRIBE.DESCRIBE_COLUMNS. all_arguments.tst all_arguments.sql allargs.*
  69. 69. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 69 First Inclina>on: Same Old, Same Old • All right then, I will grab all the informaDon from ALL_ARGUMENTS and dump it into a collecDon based on that view! Very easy... CREATE OR REPLACE PROCEDURE get_all_arguments ( package_in IN VARCHAR2) IS TYPE all_arguments_tt IS TABLE OF all_arguments%ROWTYPE INDEX BY BINARY_INTEGER; l_arguments all_arguments_tt; BEGIN FOR rec IN ( SELECT * FROM all_arguments WHERE owner = USER AND package_name = package_in) LOOP l_arguments (SQL%ROWCOUNT) := rec; END LOOP; END; Load it up! Emulate the view.
  70. 70. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 70 Then what? Write lots of code to interpret the contents... • Which programs are overloaded? Where does one overloading end and another start? l_last_program all_arguments.object_name%TYPE; l_is_new_program BOOLEAN := FALSE; l_last_overload PLS_INTEGER := -1; BEGIN FOR indx IN l_arguments.FIRST .. l_arguments.LAST LOOP IF l_arguments (indx).object_name != l_last_program OR l_last_program IS NULL THEN l_last_program := l_arguments (indx).object_name; l_is_new_program := TRUE; do_new_program_stuff; END IF; ... IF l_arguments (indx).overload != l_last_overload OR l_last_overload = -1 THEN IF l_is_new_program THEN do_first_overloading_stuff; ELSE do_new_overloading_stuff; END IF; END IF; END LOOP; END;
  71. 71. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 71 Discovery: there is a hierarchy within the ALL_ARGUMENTS data! •  Each program has zero or more overloadings, each overloading has N arguments, and each argument can have mulDple "breakouts" (my term - applies to non-scalar parameters, such as records or object types). RUN_TEST SHOW_RESULTS RESET_FLAGS Program name Overloading 1 Overloading 2 Overloading Argument 1 Argument 2 Argument 3 Argument 4 Argument 5 Argument Breakout 1 Breakout 1 Breakout 2 Breakout 3 Breakout
  72. 72. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 72 What if I reflect this hierarchy in a mul>level collec>on? • Have to build from the boLom up: TYPE breakouts_t IS TABLE OF all_arguments%ROWTYPE INDEX BY PLS_INTEGER; TYPE arguments_t IS TABLE OF breakouts_t INDEX BY PLS_INTEGER; TYPE overloadings_t IS TABLE OF arguments_t INDEX BY PLS_INTEGER; TYPE programs_t IS TABLE OF overloadings_t INDEX BY all_arguments.object_name%type; 1. Set of rows from ALL_ARGUMENTS String-based index 2. All the "breakout" info for a single argument 3. All the argument info for a single overloading 4. All the overloadings for a distinct program name
  73. 73. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 73 Then I can populate it very easily • Assigning a single record to the "lowest" level also defines each of the upper levels. • NoDce the automaDc "SELECT DISTINCT" on name that results! FOR rec IN (SELECT * FROM all_arguments) LOOP l_arguments (NVL (l_arguments.LAST, 0) + 1) := rec;   l_programs (rec.object_name) (NVL (rec.overload, 0)) (rec.position) (rec.data_level) := rec; END LOOP; I can still do the typical sequential load. But I will now also add the multi-level load in single assignment show_all_arguments.sp show_all_arguments.tst cc_smartargs.pkb/load_arguments
  74. 74. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 74 And then I can "query" the contents with a minimum of code l_programs ('TOP_SALES') (2).EXISTS (0) Is the TOP_SALES program overloaded? l_programs ('TOP_SALES') (2)(0)(0).datatype l_programs ('TOP_SALES').COUNT > 1 Is the 2nd overloading of TOP_SALES a function? What is the datatype of the RETURN clause of the 2nd overloading of TOP_SALES? And, of course, I know the beginning and end points of each program, overloading, and argument. I just use the FIRST and LAST methods on those collections!
  75. 75. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 75 Conclusions – Nested Collec>ons • The nested collecDon is a powerful, but potenDally very complicated, feature of PL/SQL. • Used correctly, it can hide complexity in the underlying data structure, and greatly simplify your algorithms. • If you find yourself saying "It shouldn't be this hard," take a look at how you are using your collecDons (or SQL). – Perhaps mulDlevel collecDons can come to the rescue!
  76. 76. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 76 Manipula>ng Nested Tables as Mul>sets • Nested tables are, from a theoreDcal standpoint, "mulDsets." – There is no inherent order to the elements. – Duplicates are allowed and are significant. – RelaDonal tables are mulDsets as well. • If a set has no order, then it has no index, so it must be manipulated as a set. • In Oracle Database 10g, Oracle added MULTISET set operators to manipulate the contents of nested tables (only). – Use in both PL/SQL blocks and SQL statements.
  77. 77. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 77 Set-Oriented Features for Nested Tables • Determine if... – two nested tables are equal/unequal – a nested table has duplicates, and remove duplicates – one nested table contains another – an element is a member of a nested table • Perform set operaDons. – Join contents of two nested tables: MULTISET UNION. – Return common elements of two nested tables with MULTISET INTERSECT. – Take away the elements of one nested table from another with MULTISET EXCEPT (oddly, not MINUS).
  78. 78. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 78 Check for equality and inequality • You can use = and <> to compare the contents of two nested tables. – But watch out! NULLs have the usual disrupDve impact. • This is an enormous advantage over wriDng a program to compare the contents of two collecDons. DECLARE TYPE clientele IS TABLE OF VARCHAR2 (64); group1 clientele := clientele ('Customer 1', 'Customer 2'); group2 clientele := clientele ('Customer 1', 'Customer 3'); group3 clientele := clientele ('Customer 3', 'Customer 1'); BEGIN IF group1 = group2 THEN DBMS_OUTPUT.put_line ('Group 1 = Group 2'); ELSE DBMS_OUTPUT.put_line ('Group 1 != Group 2'); END IF; END; 10g_compare.sql 10g_compare_nulls.sql 10g_compare_old.sql
  79. 79. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 79 Copyright 2000-2008 Steven Feuerstein - Page 79 Nested table duplicates – detec>on and removal • Use the SET operator to work with disDnct values, and determine if you have a set of disDnct values. DECLARE keep_it_simple strings_nt := strings_nt (); BEGIN keep_it_simple := SET (favorites_pkg.my_favorites); favorites_pkg.show_favorites ('FULL SET', favorites_pkg.my_favorites); p.l (favorites_pkg.my_favorites IS A SET, 'My favorites distinct?'); p.l (favorites_pkg.my_favorites IS NOT A SET, 'My favorites NOT distinct?'); favorites_pkg.show_favorites ( 'DISTINCT SET', keep_it_simple); p.l (keep_it_simple IS A SET, 'Keep_it_simple distinct?'); p.l (keep_it_simple IS NOT A SET, 'Keep_it_simple NOT distinct?'); END; authors.pkg 10g_set.sql
  80. 80. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 80 Determine if value is in nested table • Use the MEMBER OF syntax to determine if a value is in the nested table. – Much simpler than scanning the contents of a collecDon. – Performs an equality check for the enDre element; you cannot compare individual fields of records, and so on. • The implementaDon in SQL itself is quite slow. • Performance in PL/SQL is fast. in_clause.* 10g_member_of.sql
  81. 81. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 81 Does one nested table contains another? • The SUBMULTISET OF operator determines if all the elements of one nested table are in another. DECLARE TYPE nested_typ IS TABLE OF NUMBER; nt1 nested_typ := nested_typ (1, 2); nt2 nested_typ := nested_typ (3, 2, 1); BEGIN IF nt1 SUBMULTISET OF nt2 THEN ... END IF; END; authors.pkg 10g_submultiset.sql
  82. 82. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 82 UNION two nested tables together • Use UNION to join together the contents of two nested tables. • Duplicates are preserved unless you include the DISTINCT modifier. – This is the opposite of SQL UNION and UNION ALL. • The resulDng collecDon is either empty or sequenDally filled from index value 1. – You do not need to iniDalize or extend first. authors.pkg 10g_union.sql
  83. 83. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 83 Intersect two nested tables together • Use INTERSECT to find the common elements of two nested tables. • Duplicates are preserved unless you include the DISTINCT modifier. – And the ALL modifier is the default. • The resulDng collecDon is either empty or sequenDally filled from index value 1. – You do not need to iniDalize or extend first. 10g_intersect.sql
  84. 84. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 84 Take away the elements of one nested table from another • Use EXCEPT (not MINUS!) to take all elements in one nested table out of another. • Duplicates are preserved unless you include the DISTINCT modifier. – And the ALL modifier is the default. • The resulDng collecDon is either empty or sequenDally filled from index value 1. – You do not need to iniDalize or extend first. 10g_except.sql
  85. 85. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 85 Conclusions – MULTISET operators • When you need to manipulate the contents of a collecDon as a set, use a nested table. • The MULTISET operators offer a powerful, simple way to avoid wriDng lots of code. • The SET, SUBMULTISET and MEMBER operators also can come in very handy. • Watch out for results when your nested table may contain NULL elements.
  86. 86. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 86 Collec>on Best Prac>ces • Watch the PGA memory. • Hide the implementaDon details. • Use subtypes to self-document element and index by types. • Choosing the best type of collecDon
  87. 87. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 87 Watch PGA memory consump>on • Memory for collecDons is allocated from the PGA (Process Global Area). – There is a PGA for each session connected to the instance. • Large collecDons constructed by programs run by many simultaneously-connected users can cause memory errors. • Use the plsq_memory package to analyze the amount of memory used. – Or at least make sure your DBA knows you are making extensive use of collecDons. plsql_memory*.*
  88. 88. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 88 Hide the implementa>on details. • CollecDons, especially mulD-level collecDons, are very complex structures. • Hide the way you to set and get elements in a collecDon behind an API. – Procedure to set, funcDon to get. – When you have change the implement, you change in one place (single point of definiDon). multdim.sql cc_smartargs.sql
  89. 89. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 89 Use subtypes to self-document datatypes • You should avoid using base datatypes in both the TABLE OF and INDEX BY clauses. – Especially when working with string-indexed associaDve arrays. • Use SUBTYPEs to provide applicaDon-specific names that self-document both contents and intenDon. – Constants can also come in handy. string_tracker3.*
  90. 90. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 90 Choosing the best type of collec>on • Use associaDve arrays when you need to... – Work within PL/SQL code only – Sparsely fill and manipulate the collecDon – Take advantage of negaDve index values or string indexing • Use nested tables when you need to... – Access the collecDon inside SQL – Want or need to perform high level set operaDons (MULTISET) • Use varrays when you need to... – If you need to specify a maximum size to your collecDon – OpDmize performance of storing collecDon as column
  91. 91. Copyright © 2015 Oracle and/or its affiliates. All rights reserved. | Page 91 Collec>ons: Don't start coding without them. • It is impossible to write efficient, high quality PL/SQL code, taking full advantage of new features, unless you use collecDons. – From array processing to table funcDons, collecDons are required. • Learn collecDons thoroughly and apply them throughout your backend code. – Your code will get faster and in many cases much simpler than it might have been (though not always!).
  92. 92. 92

×