Oracle8 introduced the term collection to describe three new datatypes: index-by tables, nested tables, and variable arrays. These collections are quite similar and are really just conceptual riffs on the old PL/SQL table. We’ll examine each of these new types in the next three chapters.
The index-by table (or the structure formerly known as a PL/SQL table) is PL/SQL’s answer to an array. Like an array, an index-by table consists of homogeneous elements (meaning that all the elements have the same datatype) that are indexed by an integer (hence the name index-by table). Unlike arrays in other languages, PL/SQL index-by tables are one-dimensional, sparse (meaning that there can be “gaps” between elements), and unconstrained (meaning that the number of elements can grow). This chapter tests your understanding of these extremely useful structures.
6-23. | My son keeps track of every year’s favorite birthday presents in a database table. To display the contents of that table, he loads them into an index-by table, using the year as the row number: /* Filename on web page: presents.sql */ CREATE TABLE birthday ( party_date DATE, fav_present VARCHAR2(100)); INSERT INTO birthday VALUES ('01-OCT-92', 'TEENAGE MUTANT NINJA TURTLE'), INSERT INTO birthday VALUES ('01-OCT-98', 'GAMEBOY POKEMON'), DECLARE TYPE name_tt IS TABLE OF birthday.fav_present%TYPE INDEX BY BINARY_INTEGER; the_best name_tt; BEGIN FOR rec IN ( SELECT TO_NUMBER (TO_CHAR (party_date, 'YYYY')) indx, fav_present FROM birthday) LOOP the_best (rec.indx) := rec.fav_present; END LOOP; That’s all well and good, but what he really wants to do is display those favorite presents and savor the moments of his recent past. The following loops demonstrate different ways he could see this information. Which is the best approach to take and what is wrong with each of the others?
|
6-24. | The salary_ grouping package creates a matrix grouping of employees and salary ranges. The package is used as follows: DECLARE v_range salary_grouping.v_range_type; BEGIN v_range(1) := 20000; v_range(2) := 30000; v_range(3) := 75000; v_range(4) := 100000; v_range(5) := 125000; salary_grouping.build_range(v_range); salary_grouping.show_range(v_range); END; This example produces the following output, showing that three employees make more than $30,000 and less than or equal to $75,000, and two employees make more than $75,000 and less than or equal to $100,000: 20000 30000 75000 100000 125000 0 0 3 2 0 Here is a sample header for the package: CREATE OR REPLACE PACKAGE salary_grouping IS /* Type and table to store the salary groupings */ TYPE v_range_type IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; v_range_table v_range_type; /* Calculate the groupings */ PROCEDURE build_range ( p_range IN OUT v_range_type ); /* Procedure to display the calculated groupings */ PROCEDURE show_range ( p_range IN v_range_type ); -- the number of categories defined v_num_categories PLS_INTEGER; -- the longest category (for display) v_maxlen PLS_INTEGER; END salary_grouping; Write the code for the package body. |
6-25. | Wouldn’t it be great to sort the contents of an index-by table? Here is the specification of such a package for sorting VARCHAR2(30) index-by tables: CREATE OR REPLACE PACKAGE sort_routines IS -- global types for sorting TYPE v_vc230_array_type IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER; /* Overloaded sort procedures */ PROCEDURE sort_table( p_array IN OUT v_vc230_array_type, p_duplicates BOOLEAN := FALSE ); END sort_routines; The p_duplicates flag denotes whether duplicate values are to be included in the sorted array or not; the default is that duplicates are to be left out of the sorted version of the table. Write the code for the package body. |
6-26. | Index-by tables can support bidirectional cursors that allow navigation forward and backward through rows in a table (Oracle does not support true bidirectional cursor access, at least up through Oracle8i Release 8.1). Here is a package header that implements simplified bidirectional cursor capabilities for the employee table: CREATE OR REPLACE PACKAGE employee_cursor IS -- record of the employee table declared -- globally for all to see TYPE employee_record IS RECORD ( empno employee.empno%TYPE, empname employee.empname%TYPE, empsalary employee.empsalary%TYPE ); -- load the employee records into memory FUNCTION load_rows RETURN PLS_INTEGER; -- function to move to the next row FUNCTION next_row RETURN BOOLEAN; -- function to move to the previous row FUNCTION prev_row RETURN BOOLEAN; -- function to get the values for the current row FUNCTION get_row RETURN employee_record; -- function to go to a specific row FUNCTION go_row ( p_row PLS_INTEGER ) RETURN BOOLEAN; END employee_cursor; Here is an example of using this package: DECLARE v_num_employees PLS_INTEGER; v_employee employee_cursor.employee_record; BEGIN -- load the employees into memory v_num_employees := employee_cursor.load_rows; -- display the first employee IF v_num_employees > 0 THEN v_employee := employee_cursor.get_row; DBMS_OUTPUT.PUT_LINE(v_employee.empno); END IF; -- loop through the rest and display them LOOP EXIT WHEN NOT employee_cursor.next_row; v_employee := employee_cursor.get_row; DBMS_OUTPUT.PUT_LINE(v_employee.empno); END LOOP; -- wait a minute, who was that second one again? IF employee_cursor.go_row(2) THEN v_employee := employee_cursor.get_row; DBMS_OUTPUT.PUT_LINE(v_employee.empno); END IF; END; Write the code for the package body. |
18.226.82.78