1. Trang chủ
  2. » Công Nghệ Thông Tin

Oracle PL/SQL Language Pocket Reference- P13

50 306 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Nonsequential Use of PL/SQL Table
Trường học Unknown
Chuyên ngành Oracle PL/SQL
Thể loại Referenc
Định dạng
Số trang 50
Dung lượng 168,44 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Previous: 10.6 Filling the Rows of a PL/SQL Table Chapter 10PL/SQL Tables Next: 10.8 PL/SQL Table Enhancements in PL/SQL Release 2.3 10.7 Clearing the PL/SQL Table What happens when you

Trang 1

10.5.3 Nonsequential Use of PL/SQL Table

Of course, the idea of using a minimum and maximum row assumes that the rows in the table are used sequentially That is, you fill row one, then row two, etc This is a perfectly reasonable way to fill a table's rows; to do this you absolutely must know the value of the row last filled You are not, however, required to fill rows in this way You can place a value in any row of the table you wish, regardless of the primary key value of the last row you filled

The following example illustrates filling a PL/SQL table's rows randomly rather than sequentially:

countdown_test_list (1) := 'All systems go';

countdown_test_list (43) := 'Internal pressure';

countdown_test_list (255) := 'Engine inflow';

END;

In this situation, the minimum and maximum values do not have much significance

The ability to randomly place values in a table can come in very handy when the primary key value for the table's row is actually not sequentially derived, but is instead based on data in your

application This use of "intelligent" primary key values is explored in more detail in Section 10.9.2,

"Data-Smart Row Numbers in PL/SQL Tables" later in this chapter

10.5.4 Passing PL/SQL Tables as Parameters

You can also pass a PL/SQL table as a parameter in a procedure or function; with this approach you can, in a single call, pass all the values in a table into the module In the following package

specification I define two modules that pass PL/SQL tables as parameters The send_promos

procedure sends a promotional mailing to all the companies in my table The companies_overdue function returns a table filled with the names of companies that have overdue bills

PACKAGE company_pkg

IS

TYPE primary_keys_tabtype IS TABLE OF company

company_id%TYPE NOT NULL

INDEX BY BINARY_INTEGER;

company_keys_tab primary_keys_tabtype;

emp_keys_tab primary_keys_tabtype;

Trang 2

/* Table type and table for company names */

TYPE company_names_tabtype IS TABLE OF company.name%

TYPE

INDEX BY BINARY_INTEGER;

company_names_tab company_names_tabtype;

/* Parameter is a table of company primary keys */

PROCEDURE send_promos (company_table_in IN

primary_keys_tabtype);

/* Function returns a table of company names */

FUNCTION companies_overdue (overdue_date_in IN DATE)

RETURN company_names_tabtype;

/* Returns company ID for name */

FUNCTION id (name in IN company.name%TYPE)

RETURN company.company id%TYPE

END company_pkg;

Now that I have a package containing both the table type and the programs referencing those types, I can call these programs The only tricky part to remember here is that you must declare a PL/SQL table based on the type before you can use any of the programs Here is an example of returning a PL/SQL table as a function's return value:

CREATE OR REPLACE PROCEDURE

Trang 3

Notice that I could also have avoided declaring my own PL/SQL table, cnames, by using the

predefined table in the package:

Trang 4

/* Delete all the rows from the company names table */ company_pkg.company_names_tab.DELETE;

END company_pkg;

Previous: 10.4 Declaring a

PL/SQL Table

Oracle PL/SQL Programming, 2nd Edition

Next: 10.6 Filling the Rows

of a PL/SQL Table10.4 Declaring a PL/SQL

Trang 5

Previous: 10.5 Referencing

and Modifying PL/SQL

Table Rows

Chapter 10PL/SQL Tables

Next: 10.7 Clearing the PL/

SQL Table

10.6 Filling the Rows of a PL/SQL Table

You can assign values to rows of a table in several ways:

countdown_test_list (43) := 'Internal pressure';

company_names_table (last_name_row) := 'Johnstone

In the following example, I use a WHILE loop to fill and then display a PL/SQL date table with the next set of business days, as specified by the ndays_in parameter:

Trang 6

/* Filename on companion disk: bizdays.sp */

CREATE OR REPLACE PROCEDURE show_bizdays

(start_date_in IN DATE := SYSDATE, ndays_in IN

assignment operator (:=) to transfer the values of one table to the other The following example contains an example of an aggregate table assignment:

DECLARE

TYPE name_table IS TABLE OF VARCHAR2(100) INDEX BY

BINARY_INTEGER;

old_names name_table;

Trang 7

Previous: 10.5 Referencing

and Modifying PL/SQL

Table Rows

Oracle PL/SQL Programming, 2nd Edition

Next: 10.7 Clearing the PL/

Trang 8

Previous: 10.6 Filling the

Rows of a PL/SQL Table

Chapter 10PL/SQL Tables

Next: 10.8 PL/SQL Table Enhancements in PL/SQL Release 2.3

10.7 Clearing the PL/SQL Table

What happens when you are done with a PL/SQL table and want to remove it from memory? If a PL/SQL table is like a table, we should be able to DELETE the rows of that table or DROP it entirely, right? It's a nice idea, but you can't perform a SQL DELETE statement on a PL/SQL table because it

is not stored in the database You also cannot DROP a PL/SQL table

You can set a single row to NULL with the following kind of assignment:

company_names_table (num_rows) := NULL;

But this assignment doesn't actually remove the row or make it undefined; it just sets the value of the row to NULL

The only way to actually empty a PL/SQL table of all rows is to perform an aggregate assignment with a table that is empty a table, that is, with no rows defined

With this approach, for every PL/SQL table you want to be able to empty, you declare a parallel, empty table of the same table type When you are finished working with your table, simply assign the empty table to the actual table This will unassign all the rows you have used The following example demonstrates this technique:

Trang 9

/* The closest you can come to "dropping" a PL/SQL table */

company_names_tab := empty_company_names_tab;

END;

NOTE: PL/SQL Release 2.3 offers a DELETE operator so that you can delete all or

some rows of a PL/SQL table

Previous: 10.6 Filling the

Rows of a PL/SQL Table

Oracle PL/SQL Programming, 2nd Edition

Next: 10.8 PL/SQL Table Enhancements in PL/SQL Release 2.3

10.6 Filling the Rows of a PL/

Trang 10

Previous: 10.7 Clearing the

PL/SQL Table

Chapter 10PL/SQL Tables

Next: 10.9 Working with PL/SQL Tables

10.8 PL/SQL Table Enhancements in PL/SQL Release 2.3

PL/SQL Release 2.3 offers significantly enhanced functionality for PL/SQL tables These new

features include:

column of the PL/SQL table could only be a scalar datatype, such as VARCHAR2 or

BOOLEAN or DATE Release 2.3 allows you to define table types whose element datatype is defined with the %ROWTYPE declaration attribute or is a named RECORD type

and procedures which return information about, or modify the contents of, a PL/SQL table These operations are shown in Table 10.1

These new features allow you to use PL/SQL tables for a wider range of applications and also

manipulate the data in tables in a more natural and efficient manner You can now create local PL/SQL data structures which mimic precisely the structure of a table stored in the database You do not have to create separate tables and manage them in parallel to emulate the multiple-column SQL table structure

You can use the built-ins to obtain PL/SQL table information that previously was unavailable For example, you can use the COUNT function to determine the number of elements defined in a table You no longer have to keep track of that number yourself

Table 10.1: PL/SQL Release 2.3 Built-in Functions and Procedures for Tables

Operator Description

COUNT Returns the number of elements currently contained in the PL/SQL table

DELETE Deletes one or more elements from the PL/SQL table

Trang 11

EXISTS Returns FALSE if a reference to an element at the specified index would raise the

NO_DATA_FOUND exception

FIRST Returns the smallest index of the PL/SQL table for which an element is defined

LAST Returns the greatest index of the PL/SQL table for which an element is defined

NEXT Returns the smallest index of the PL/SQL table containing an element which is greater

than the specified index

PRIOR Returns the greatest index of the PL/SQL table containing an element which is less

than the specified index

These functions and procedures are described in detail later in this chapter

When you do create a PL/SQL table based on a record structure, that record may only be composed

of scalar fields A nested record type (in which a field in the record is yet another record type) may not be used to define a table type

The following examples illustrate the different ways to declare table types based on records:

TYPE local_emp_table IS TABLE OF employee%ROWTYPE INDEX BY BINARY_INTEGER;

Trang 12

CURSOR emp_cur IS SELECT * FROM employee;

TYPE cursor_emp_table IS TABLE OF emp_cur%ROWTYPE INDEX BY BINARY_INTEGER;

TYPE emp_rectype IS RECORD (employee_id INTEGER, emp_name VARCHAR2(60));

TYPE emp_table IS TABLE OF emp_rectype INDEX BY BINARY_INTEGER;

Notice that when you use a programmer-defined record type you do not append the %ROWTYPE attribute to the record type That is only done when you are using a table-based or cursor-based

record

10.8.1.1 Referencing fields of record elements in PL/SQL tables

References to fields of elements of PL/SQL tables which are records have the following syntax:

<table name>(<index expression>).<field name>

where <table name> is the name of the table, <index expression> is an expression (constant, variable,

or computed expression) which evaluates to a number and <field name> is the name of the field in the record used to define the PL/SQL table

If, for example, you have created a PL/SQL table named emp_tab based on a record structure with a field named emp_name, then the following assignment sets the employee name in the 375th row of the PL/SQL table to SALIMBA:

Trang 13

Returns the name of the company found in the tenth row of the table.

You can improve the readability of such a statement by separating it as follows:

current_company_rec := best_company(1995)(10);

DBMS_OUTPUT.PUT_LINE

(current_company.company_name || ' was tenth best!')

where current_company_rec is a record defined with the same type as the RETURN clause of the best_company function Now you have two statements where only one is really needed, but the code can be more easily understood and therefore maintained

10.8.1.2 Assigning records in PL/SQL tables

You can assign a whole record fetched from the database directly into the row of a PL/SQL table as shown below (where both the cursor and the PL/SQL table use the same company%ROWTYPE row type declaration):

Trang 14

FOR company_rec IN company_cur

3, Built-In Functions of this book It employs a "member method" syntax, common in object-oriented

languages such as C++

To give you a feeling for member-method syntax, consider the LAST function It returns the greatest index value in use in the PL/SQL table Using standard function syntax, you might expect to call LAST as follows:

IF LAST (company_table) > 10 THEN /* Invalid syntax */

In other words, you would pass the PL/SQL table as an argument In contrast, by using the method syntax, the LAST function is a method which "belongs to" the object, in this case the PL/SQL table So the correct syntax for using LAST is:

member-IF company_table.LAST > 10 THEN /* Correct syntax */

The general syntax for calling these PL/SQL table built-ins is either of the following:

<table name>.<operation>

<table name>.<operation>(<index number> [,

<index_number>])

The following statement, for example, returns TRUE if the 15th row of the company_tab PL/SQL table is defined:

Trang 15

By using the member-method syntax, Oracle is able to distinguish the PL/SQL table functions such

as EXISTS and DELETE from the SQL operations of the same name (which never appear with qualified notation)

dot-The following sections describe each of the table built-ins

10.8.2.1 The COUNT function

The COUNT function returns the number of elements currently defined in the PL/SQL table The specification for the function is:

FUNCTION COUNT RETURN INTEGER;

You call COUNT as follows:

total_rows := emp_table.COUNT;

Notice that if the emp_table structure were defined inside a package, then double dot notation would

be needed to get the count:

total_rows := employee_pkg.emp_table.COUNT;

Prior to PL/SQL Release 2.3, the only way to determine this count was to manually keep track of the number of elements defined in the table

10.8.2.2 The DELETE procedure

The DELETE procedure deletes elements from the specified PL/SQL table The specifications for the procedure are overloaded, as shown in the following table

PROCEDURE DELETE; Just as with SQL, this simplest form of the

DELETE build-in (which takes no arguments at all) has the most sweeping impact: delete all rows from the PL/SQL table

PROCEDURE DELETE

(index_in IN INTEGER);

Delete the row specified by that index

Trang 16

If any of the arguments to DELETE is NULL, then the operation does not remove any rows at all You call DELETE as shown in the following examples:

10.8.2.3 The EXISTS function

The EXISTS function returns TRUE if an element is defined at the specified index in a PL/SQL table Otherwise, it returns FALSE The specification for the function is:

FUNCTION EXISTS (index_in IN INTEGER) RETURN BOOLEAN;

You call EXISTS as follows:

IF seuss_characters_table.EXISTS(1) THEN

Prior to PL/SQL Release 2.3, you could emulate the EXISTS function with your own function

looking something like this:

/* Filename on companion disk: rowexist.sf */

FUNCTION row_exists

(table_in IN <table type>, row_in IN INTEGER) RETURN

Trang 17

10.8.2.4 The FIRST function

The FIRST function returns the lowest value index for which an element is defined in the specified PL/SQL table The specification for the function is:

FUNCTION FIRST RETURN INTEGER;

You call FIRST as follows:

first_entry_row := employee_table.FIRST;

If the PL/SQL table does not contain any elements at all, FIRST returns NULL

10.8.2.5 The LAST function

The LAST function returns the highest value index for which an element is defined in the specified PL/SQL table The specification for the function is:

FUNCTION LAST RETURN INTEGER;

You call LAST as follows:

last_entry_row := employee_table.LAST;

If the PL/SQL table does not contain any elements at all, LAST returns NULL

If you plan to use the PL/SQL table to fill rows sequentially from, say, the first row, you will want to make sure to use the NVL function (see Chapter 13, Numeric, LOB, and Miscellaneous Functions) to convert the NULL to a zero, as shown in this example

Trang 18

The following block uses a cursor FOR loop to transfer data from the database to a PL/SQL table of records When the first record is fetched, the company_table is empty, so the LAST operator will return NULL NVL converts that value to zero I then add one and I am on my way:

FOR company_rec IN company_cur

10.8.2.6 The NEXT function

The NEXT function returns the next greater index after the specified index at which some element is defined in the specified PL/SQL table The specification for the function is:

FUNCTION NEXT (index_in IN INTEGER) RETURN INTEGER;

You call NEXT as follows:

next_index := employee_table.NEXT (curr_index);

Remember that PL/SQL tables are sparse: if the tenth and 2005th rows are defined, there is no

guarantee that the 11th row is also defined NEXT gives you a way to find the next defined element,

"skipping over" any undefined row numbers

The table.NEXT procedure will return NULL if there aren't any elements defined after the specified row

10.8.2.7 The PRIOR function

The PRIOR function returns the prior greater index after the specified index at which some element is defined in the specified PL/SQL table The specification for the function is:

FUNCTION PRIOR (index_in IN INTEGER) RETURN INTEGER;

You call PRIOR as follows:

prev_index := employee_table.PRIOR (curr_index);

Trang 19

Remember that, as we described in the preceding section, PL/SQL tables are sparse PRIOR gives you a way to find the previously defined element, "skipping over" any undefined row numbers

The table.PRIOR procedure will return NULL if there aren't any elements defined before the specified row

Previous: 10.7 Clearing the

PL/SQL Table

Oracle PL/SQL Programming, 2nd Edition

Next: 10.9 Working with PL/SQL Tables

Trang 20

Previous: 10.8 PL/SQL

Table Enhancements in PL/

SQL Release 2.3

Chapter 10PL/SQL Tables

Next: III Built-In Functions

10.9 Working with PL/SQL Tables

The remainder of this chapter provides you with lots of examples of ways to use PL/SQL tables in your applications

10.9.1 Transferring Database Information to PL/SQL Tables

You cannot use a SQL SELECT statement to transfer data directly from a database table to a PL/SQL table You need to take a programmatic approach A cursor FOR loop usually makes the most sense for this process, which requires the following steps:

1 Define a PL/SQL table TYPE for each datatype found in the columns of the database table

2 Declare PL/SQL tables which will each receive the contents of a single column

3 Declare the cursor against the database table

4 Execute the FOR loop The body of the loop will contain a distinct assignment of one column into one PL/SQL table

In PL/SQL Release 2.3, this process would be much simpler You could define a PL/SQL table with the same structure as the database table by creating a table-based record Prior to that release,

unfortunately, you need a separate PL/SQL table for each column You do not, on the other hand, need a separate table TYPE for each column If you have two date columns, for example, you can declare two separate PL/SQL tables both based on the same TYPE

In the following example I load the company ID, incorporation date, and filing date from the database table to three different PL/SQL tables Notice that there are only two types of PL/SQL tables

declared:

/* Filename on companion disk: db2tab1.sql (see db2tab2

sql for the PL/SQL Release 2.3 version of same transfer)

*/

DECLARE

/* The cursor against the database table */

CURSOR company_cur

Trang 21

/* The cursor FOR loop */

FOR company_rec IN company_cur

10.9.2 Data-Smart Row Numbers in PL/SQL Tables

As I've mentioned, one of the most interesting and unusual aspects of the PL/SQL table is its sparseness I can have a value in the first row and in the 157th row of the table, with nothing in between This feature is directly related to the fact that a PL/SQL table is unconstrained Because there is no limit on the number of rows in a table, PL/SQL does not set aside the memory for that

Trang 22

table at the time of creation, as would normally occur with an array

When you use the PL/SQL table to store and retrieve information sequentially, this sparse quality doesn't have any real significance The ability to store data nonsequentially can, however, come in very handy Because the row number does not have to be sequentially generated and used, it can represent data in your application In other words, it can be "data-smart."

Suppose you want to use a PL/SQL table to store the text of messages associated with numeric error codes These error codes are patterned after Oracle error codes, with ranges of values set aside for different aspects of the application: 1000-1999 for employee-related errors, 5000-5999 for company-related errors, etc When a user action generates an error, the error number is passed to a procedure which then looks up and displays the message By storing this information in PL/SQL tables, you avoid a lookup against the remote database

Let's take a look at sequential and indexed access to implement this functionality

10.9.2.1 Sequential, parallel storage

One possible way to implement this procedure is to create two tables: one that holds the error codes (stored sequentially in the table) and another that holds the messages (also stored sequentially) When

an error is encountered, the procedure scans sequentially through the PL/SQL table of codes until it finds a match The row in which the code is found is also the row in the PL/SQL message table; it uses the row to find the message and then displays it Figure 10.2 shows the correlation between these two tables

Figure 10.2: Using sequential access to correlate contents of two tables

The code needed to implement this algorithm is shown in the following procedure The procedure assumes that the two PL/SQL tables have already been loaded with data The error_pkg.last_row variable is the last row containing an error code:

Trang 23

/* Filename on companion disk: seqretr.sp */

PROCEDURE display_error (errcode_in IN NUMBER)

A straightforward, sensible approach, right? Yes and no Yes, it is straightforward No, in the context

of the PL/SQL table, it is not sensible This module insists on performing a sequential scan when such a step is not necessary

10.9.2.2 Using the index as an intelligent key

A much simpler way to accomplish this same task is to use the error code itself as the primary key value for the row in the error messages table Then I need only one table to hold the error messages (see Figure 10.3)

Figure 10.3: Using indexed access to retrieve value with intelligent key row

Trang 24

Instead of matching the error code and then using the primary key to locate the corresponding message, the error code is itself the index into the PL/SQL table By using a single table and data-smart values for the primary key, the display_error procedure boils down to the code shown below:

/* Filename on companion disk: indretr.sp */

PROCEDURE display_error (errcode_in IN NUMBER) IS

So if you ever find yourself reading sequentially through a PL/SQL table, take a step back and consider what data you need to obtain and how it is being stored Sometimes you do need to store

Trang 25

data sequentially (when you use a PL/SQL table, for example, to implement a stack data structure) Frequently, however, you can simplify your life and your code by using data-smart values in your PL/SQL table

10.9.3 Displaying a PL/SQL Table

When you work with PL/SQL tables, you often want to verify the contents of the table The usual verification method is to display the contents of each row using DBMS_OUTPUT This sounds like a simple enough task In the most basic scenario where you have a sequentially filled table, the code is indeed straightforward

The following procedures shows the small amount of code required to display a table which has rows

1 through n defined, where n is passed as a parameter to the procedure The procedure displays a

VARCHAR2 table; to display DATE or NUMBER tables, you simply need to use TO_CHAR to convert the value in the call to PUT_LINE:

/* Filename on companion disk: disptab1.sp */

/* For each row in the table */

FOR table_row IN 1 number_of_rows_in

Of course, not all PL/SQL tables can be filled in ways which are displayed as easily as the one shown above To start with, the display_table procedure makes many assumptions about its table profile (although very few tables actually fit this profile) These include the following:

NO_DATA_FOUND

Ngày đăng: 07/11/2013, 19:15