通过下面的例子,好好研究一下ORACLE提供给我们的功能吧!
This module describes how to utilize some of the latest PL/SQL capabilities to optimize performance and increase the efficiency of your PL/SQL applications..
Upon completion of this module, you should be able to:
Use an Associative Array |
|
Use the UTL_FILE package to manage access to directories, handle raw data, and copy, rename and delete files | |
Use Bulk binding in native dynamic SQL | |
Use PL/SQL RECORDs to access and manipulate changes to the database |
The prerequisites for this lesson are:
Completed the Preinstallation Tasks module |
|
Completed the Installing the Oracle9i Database module |
|
Download and unzip plsql.zip into your working directory |
The following list represents some useful reference material should you need additional information on the topics in this module:
Documentation: PL/SQL User's Guide and Reference |
|
Documentation: Supplied PL/SQL Packages and Types Reference | |
PL/SQL Whitepapers and Code Examples on OTN |
The features you will explore in this lesson are:
1. | Using Associative Arrays |
2. | Using the UTL_FILE Package |
3. | Using Bulk Binding in Native Dynamic SQL |
4. | Using PL/SQL Records |
Back to List
In Oracle9i Database Release 2, PL/SQL index-by tables, now known as associative arrays, have been extended to allow the array to be indexed using the VARCHAR2 datatype. The index-by-varchar2 table is optimized for efficiency of lookup on a non-numeric key, where the notion of sparseness is not applicable. The index-by-*integer table (where *integer can be either pls_integer or binary_integer) in contrast is optimized for compactness of storage on the assumption that the data is dense. This implies that there might be cases where, even though the key is inherently numeric, it is better to represent the table as index-by-varchar2 table via a To_Char conversion.
In this section of the lesson, you will define a table type containing a table of records that are indexed by the employee e-mail ID, declare an identifier of the table type, and access an element of the table. Perform the following steps:
1. | You will create a table of employee records and index the table using the employees' e-mail ID. Open a SQL*Plus session and execute the following script: @assocarray SET SERVEROUTPUT ON
DECLARE
/* Index the table by a VARCHAR2 column type */
TYPE emp_tab_type IS TABLE
OF employees%ROWTYPE
INDEX BY employees.email%TYPE;
v_emp_tab emp_tab_type;
/* Hold the character index here */
v_email employees.email%TYPE;
BEGIN
/* Populate the table */
v_emp_tab('COLSEN').first_name := 'Christopher';
v_emp_tab('CDAVIES').first_name := 'Curtis';
v_emp_tab('CVISHNEY').first_name := 'Clara';
/* Get the first index value */
v_email := v_emp_tab.FIRST();
/* Display the entire table */
WHILE v_email IS NOT NULL LOOP
dbms_output.put_line
(' Index: ' || v_email);
dbms_output.put_line
(' Name: ' || v_emp_tab(v_email).first_name);
/* Get the next index value */
v_email := v_emp_tab.NEXT(v_email);
END LOOP;
END;
/
|
Back to List
In Oracle9i Database Release 2, there have been many changes to the UTL_FILE package. These include security enhancements using the CREATE DIRECTORY statement, copying, deleting and renaming files, and handling raw data. You will examine the following new capabilities:
1. | Using the CREATE DIRECTORY Statement to manage access to directories |
2. | Handling Raw Data |
3. | Copying, Deleting and Renaming Files |
Back to List
Both server and client side PL/SQL programs can use the UTL_FILE package although file system access is always on the server host. Prior releases controlled the server side access through the UTL_FILE_DIR initialization parameter. With Oracle9i Database Release 2, the server side access is controlled through the directory object feature that is enabled through the CREATE DIRECTORY command. The CREATE DIRECTORY privilege is granted only to SYS and SYSTEM by default. directory objects are always owned by SYS. Perform the following steps:
1. | You will create a directory and grant read access to HR. Open a SQL*Plus session and execute the following script: @dircreate SET ECHO ON
|
2. | HR has access to the files located in the d:/wkdir directory. Subdirectory access is not available. Accessing any file within the d:/wkdir directory must follow the case sensitivity rules as required by the operating system. All other users trying to access a file within this directory receive an Oracle exception: ORA-29289: directory access denied. You can catch this exception by using the UTL_FILE package exception ACCESS_DENIED. To show how this works, logon as HR and execute the following script: @dirtestsys connect hr/[email protected]
|
3. | Now you can test access on the USER_DIR. From your SQL*Plus session, execute the following script: @dirtestuser connect hr/[email protected] You can now check your working directory to see that the userdata.txt file is there.
|
Back to List
The UTL_FILE package has added four new functions to be used to process files containing RAW data; GET_RAW, PUT_RAW, FSEEK and FGETPOS. In this example, you will examine random access using FSEEK and GET_RAW. You will create a file using GET_RAW and write three records into the file in a particular order. You will then re-open the file for reading and use FSEEK to position at the start of a record and use GET_RAW to read one record.
Perform the following steps:
1. | From your SQL*Plus sessioin, execute the following script: @rawdata
connect hr/[email protected]
set serveroutput on In this case, you read the last record in the file first and the first record in the file second. |
Back to List
Four new procedures have been added to UTL_FILE to allow the file access activities of removing, copying, finding attributes, and renaming operating system files: UTL_FILE.FGETATTR, UTL_FILE.FCOPY, UTL_FILE.FRENAME, and UTL_FILE.FREMOVE.
1. | The UTL_FILE.FGETATTR procedure reads and returns the attributes of a disk file. From your SQL*Plus session, execute the following script: @fgetattr connect hr/[email protected]
set serveroutput on
|
2. | The UTL_FILE.FCOPY procedure copies a contiguous portion of a text file to a new file. The entire file is copied if the start line and end line parameters are omitted. From your SQL*Plus session session, execute the following script: @fcopy connect hr/[email protected] set serveroutput on In Windows Explorer, if you take a look in the physical directory d:/wkdir you will see that there are two files userdata.txt and copy.txt.
|
3. | The UTL_FILE.FRENAME procedure renames an existing file to a new name. You will rename the file userdata.txt to userdata2.txt in the USER_DIR directory. Execute the following SQL in SQL*Plus: @frename connect hr/[email protected] In Windows Explorer, you will see that the file has been renamed.
|
4. | The UTL_FILE.FREMOVE procedure removes an operating system file. You will remove the userdata2.txt file from the USER_DIR directory. Execute the following script in SQL*Plus: @fremove connect hr/[email protected]
In Windows Explorer, you will see that the file has been deleted.
|
Back to List
Bulk-bind features of PL/SQL in Oracle9i have been enhanced to support more convenient and efficient bulk-bind operations, and to provide an error-handling mechanism. One of the restrictions about bulk binds in earlier releases of the Oracle server was that variables defined in SELECT and FETCH clauses could not be collections of records. In Oracle9i the bulk-binding feature has been enhanced to allow users to retrieve multiple rows easily from database tables. Bulk binding of records used in INSERT and UPDATE statements is also now supported.
In addition, previously used bulk-bind operations, such as FORALL INSERT/UPDATE/DELETE, stopped immediately whenever there were errors during their execution, and an exception was then be raised. In certain applications, it is better to handle the exception and continue processing. In Oracle9i an error handling mechanism has been incorporated such that errors during a bulk-bind operation are collected and returned together when the operation has been completed. Perform the following steps:
1. | You will use EXECUTE IMMEDIATE to execute a query to retrieve several employee IDs with one call to the database. From your SQL*Plus session, execute the following script: @bulkcollect set echo on In Oracle9i, you can take advantage of the performance of bulk binding using dynamic SQL. Prior to Oracle9i, you could only use static SQL as the following example illustrates: set echo on
|
2. | Input bind variables of a SQL statement can be bound by the FORALL control statement and USING clause. You will use bulk binding to execute an INSERT statement. You will use EXECUTE IMMEDIATE to execute an INSERT statement passing two collection variables. The two collection variables are ids and names and they contain all the department_id and department_name values, respectively. As a result, you will create several rows using one INSERT statement with one call to the database. From your SQL*Plus session, execute the following script: @bulkinsert set serveroutput on The above example takes advantage of the performance of bulk binding using dynamic SQL. Prior to Oracle9i, the following example illustrates the static SQL: set serveroutput on |
3. | Only DML statements have OUT binds. When bulk-binding, these must be bound by the RETURNING BULK COLLECT INTO clause. You will use native dynamic SQL to execute an UPDATE statement by passing a variable v_sal for the value to be used for the update. All the updated salaries are then returned, using a collection variable saltab. From your SQL*Plus session, execute the following script: @bulkupdate set serveroutput on The Oracle9i code is shown above. To produce the same results prior to Oracle9i, the code would be as follows: set serveroutput on
|
4. | Starting with Oracle9i, to handle exceptions encountered during a BULK BIND operation, you can add the keyword SAVE EXCEPTIONS to your FORALL statement. Previously, if any one row failed during the FORALL loop, the loop execution was terminated. SAVE_EXCEPTIONS allows the loop to continue processing and is required if you want the loop to continue. From your SQL*Plus session, execute the following script: @bulkexception set serveroutput on In this case, 5 errors were identified, however, the delete statement was run for each of the 9 values identified in the num_tab table. |
Back to List
In Oracle9i Database Release 2, you can insert into or update a SQL table by specifying a PL/SQL record variable, instead of specifying each record attribute separately. You can also select entire rows into a PL/SQL table of records, instead of using a separate PL/SQL table for each SQL column.
In previous releases of Oracle database, you must declare one table of scalar data type to retrieve each column of a database table or to store a set of values into a column of the database table. For example, if you want to retrieve a set of rows that contains ten columns, you might need to declare ten tables of scalar datatypes and enumerate each column in the SQL statement. In Oracle9i Database Release 2, you can declare one table of PL/SQL record that contains all the required columns and use that record to retrieve data from or manipulate data in the database table. This produces more readable code and better performance.
To make use of an entire row of a table in your PL/SQL program, you can declare a table of records using %ROWTYPE datatype. This provides schema independence. Any change to the columns of the database table does not require changes to your PL/SQL program. In previous releases, you can use %ROWTYPE only for performing single-row operations. In Oracle9i Database Release 2, this is extended to multiple-row retrieval and DML also.
Perform the following steps:
1. | In previous versions of Oracle database, you could only bulk-fetch from a cursor into multiple collections of column types. You will select all departments that are not at location 1700 into a PL/SQL table of records. From your SQL*Plus session, execute the following script: @rec_select set serveroutput on
|
2. | In Oracle9i Database Release 2 you can also select or fetch rows into a PL/SQL table of records, instead of using a separate PL/SQL table for each SQL column. From your SQL*Plus session, execute the following script: @rec_bulkfetch set serveroutput on
|
3. | You will INSERT a row using a PL/SQL record. From your SQL*Plus session, execute the following script: @rec_insert DECLARE
|
4. | Now you will update that same row with a PL/SQL record. From your SQL*Plus session, execute the following script: @rec_update DECLARE
|
5. | You can include a RETURNING clause in an INSERT, UPDATE, or DELETE statement to return column values from the affected row into a PL/SQL record variable. This eliminates the need to select the row after an insert or update, or before a delete. You can use this clause only when operating on exactly one row. From your SQL*Plus session, execute the following script: @rec_delete set serveroutput on
|
In this module, you should have learned how to:
Use an Associative Array |
|
Use the UTL_FILE package to manage access to directories, handle raw data, and copy, rename and delete files | |
Use Bulk binding in native dynamic SQL | |
Use PL/SQL RECORDs to access and manipulate changes to the database |