Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 50 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
50
Dung lượng
264,27 KB
Nội dung
Consider partial output from the preceding example:
Zip: 06820
Names(1): Scrittorale
Names(2): Padel
Names(3): Kiraly
Zip: 06830
Names(1): Dennis
Names(2): Meshaj
Names(3): Dalvi
Zip: 06880
Names(1): Miller
Names(2): Cheevens
Zip: 06903
Names(1): Segall
Names(2): Annina
Zip: 07003
Names(1): Wicelinski
Names(2): Intal
Zip: 07010
Names(1): Lopez
Names(2): Mulroy
Names(3): Velasco
Names(4): Kelly
Names(5): Tucker
Names(6): Mithane
PL/SQL procedure successfully completed.
LAB 16.2
372
Lab 16.2 Exercises
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
LAB 16.3
Collections of Records
LAB OBJECTIVE
After completing this lab, you will be able to
.
Use collections of records
In the previous lab you saw an example of a nested record in which one of the record fields was
defined as an associative array. PL/SQL also lets you define a collection of records (such as an
associative array whose element type is a cursor-based record, as shown in the following
example).
FOR EXAMPLE
DECLARE
CURSOR name_cur IS
SELECT first_name, last_name
FROM student
WHERE ROWNUM <= 4;
TYPE name_type IS TABLE OF name_cur%ROWTYPE
INDEX BY BINARY_INTEGER;
name_tab name_type;
v_counter INTEGER := 0;
BEGIN
FOR name_rec IN name_cur LOOP
v_counter := v_counter + 1;
name_tab(v_counter).first_name := name_rec.first_name;
name_tab(v_counter).last_name := name_rec.last_name;
DBMS_OUTPUT.PUT_LINE('First Name('||v_counter||'): '||
name_tab(v_counter).first_name);
DBMS_OUTPUT.PUT_LINE('Last Name('||v_counter||'): '||
name_tab(v_counter).last_name);
END LOOP;
END;
LAB 16.3
373
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
▼
In the declaration portion of this example, you define the name_cur cursor, which returns the
first and last names of the first four students. Next, you define an associative array type whose
element type is based on the cursor defined previously using the %ROWTYPE attribute. Then
you define an associative array variable and the counter that is used later to reference individ-
ual rows of the associative array.
In the executable portion of the example, you populate the associative array and display its
records on the screen. Consider the notation used in the example when referencing individual
elements of the array:
name_tab(v_counter).first_name
and
name_tab(v_counter).last_name
Notice that to reference each row of the array, you use the counter variable, just like in all previ-
ous examples. However, because each row of this table is a record, you must also reference indi-
vidual fields of the underlying record.
This example produces the following output:
First Name(1): Fred
Last Name(1): Crocitto
First Name(2): J.
Last Name(2): Landry
First Name(3): Laetia
Last Name(3): Enison
First Name(4): Angel
Last Name(4): Moskowitz
PL/SQL procedure successfully completed.
LAB 16.3 EXERCISES
This section provides exercises and suggested answers, with discussion related to how those answers
resulted. The most important thing to realize is whether your answer works. You should figure out the
implications of the answers and what the effects are of any different answers you may come up with.
16.3.1 Use Collections of Records
In this exercise, you learn more about collections of records.
Complete the following tasks:
A) Modify the script used earlier in this lab. Instead of using an associative array, use a nested table.
ANSWER: The script should look similar to the following. Changes are shown in bold.
ch16_4a.sql, version 1.0
SET SERVEROUTPUT ON
DECLARE
CURSOR name_cur IS
SELECT first_name, last_name
LAB 16.3
374
Lab 16.3 Exercises
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
FROM student
WHERE ROWNUM <= 4;
TYPE name_type IS TABLE OF name_cur%ROWTYPE;
name_tab name_type := name_type();
v_counter INTEGER := 0;
BEGIN
FOR name_rec IN name_cur LOOP
v_counter := v_counter + 1;
name_tab.EXTEND;
name_tab(v_counter).first_name := name_rec.first_name;
name_tab(v_counter).last_name := name_rec.last_name;
DBMS_OUTPUT.PUT_LINE('First Name('||v_counter||'): '||
name_tab(v_counter).first_name);
DBMS_OUTPUT.PUT_LINE('Last Name('||v_counter||'): '||
name_tab(v_counter).last_name);
END LOOP;
END;
In the preceding script, name_tab is declared as a nested table. As a result, at the time of its
declaration, it is initialized. In other words, name_tab is empty but non-null. Furthermore, as
soon as the name_tab table is initialized, its size must be increased before it can be populated
with the next record.
B) Modify the script used earlier in this lab. Instead of using an associative array, use a varray.
ANSWER: The script should look similar to the following. Changes are shown in bold.
ch16_4b.sql, version 2.0
SET SERVEROUTPUT ON
DECLARE
CURSOR name_cur IS
SELECT first_name, last_name
FROM student
WHERE ROWNUM <= 4;
TYPE name_type IS VARRAY(4) OF name_cur%ROWTYPE;
name_tab name_type := name_type();
v_counter INTEGER := 0;
BEGIN
FOR name_rec IN name_cur LOOP
v_counter := v_counter + 1;
name_tab.EXTEND;
name_tab(v_counter).first_name := name_rec.first_name;
name_tab(v_counter).last_name := name_rec.last_name;
DBMS_OUTPUT.PUT_LINE('First Name('||v_counter||'): '||
name_tab(v_counter).first_name);
LAB 16.3
Lab 16.3 Exercises
375
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
DBMS_OUTPUT.PUT_LINE('Last Name('||v_counter||'): '||
name_tab(v_counter).last_name);
END LOOP;
END;
In this version of the script, name_tab is declared as a varray with four elements. As in the previ-
ous version, the collection is initialized and its size is incremented before it is populated with the
new record.
Both scripts, ch16_4a.sql and ch16_4b.sql, produce output identical to the original example:
First Name(1): Fred
Last Name(1): Crocitto
First Name(2): J.
Last Name(2): Landry
First Name(3): Laetia
Last Name(3): Enison
First Name(4): Angel
Last Name(4): Moskowitz
PL/SQL procedure successfully completed.
C)
Modify the script used at the beginning of this lab. Instead of using a cursor-based record, use a
user-defined record.The new record should have three fields: first_name, last_name, and
enrollments.The last field will contain the total number of courses in which a student is
currently enrolled.
ANSWER: The script should look similar to the following. Changes are shown in bold.
ch16_4c.sql, version 3.0
SET SERVEROUTPUT ON
DECLARE
CURSOR name_cur IS
SELECT first_name, last_name, COUNT(*) total
FROM student
JOIN enrollment USING (student_id)
GROUP BY first_name, last_name;
TYPE student_rec_type IS RECORD
(first_name VARCHAR2(15),
last_name VARCHAR2(30),
enrollments INTEGER);
TYPE name_type IS TABLE OF student_rec_type
INDEX BY BINARY_INTEGER;
name_tab name_type;
v_counter INTEGER := 0;
BEGIN
FOR name_rec IN name_cur LOOP
v_counter := v_counter + 1;
name_tab(v_counter).first_name := name_rec.first_name;
name_tab(v_counter).last_name := name_rec.last_name;
LAB 16.3
376
Lab 16.3 Exercises
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
name_tab(v_counter).enrollments := name_rec.total;
IF v_counter <= 4 THEN
DBMS_OUTPUT.PUT_LINE('First Name('||v_counter||'): '||
name_tab(v_counter).first_name);
DBMS_OUTPUT.PUT_LINE('Last Name('||v_counter||'): '||
name_tab(v_counter).last_name);
DBMS_OUTPUT.PUT_LINE('Enrollments('||v_counter||'): '||
name_tab(v_counter).enrollments);
DBMS_OUTPUT.PUT_LINE (' ');
END IF;
END LOOP;
END;
In the declaration portion of the script, the cursor SELECT statement has been modified so that for
each student it returns the total number of enrollments. Next, the user-defined record type,
student_rec_type, is declared so that it can be used as the element type for the associative
array type, name_type.
In the executable portion of the script, the associative array,
name_tab, is populated using the
cursor FOR loop. Next, the index counter variable, v_counter, is evaluated using the IF-THEN
statement so that only the first four records of the index-by table are displayed on the screen.
When run, this script produces the following output:
First Name(1): A.
Last Name(1): Tucker
Enrollments(1): 1
First Name(2): Adele
Last Name(2): Rothstein
Enrollments(2): 1
First Name(3): Adrienne
Last Name(3): Lopez
Enrollments(3): 1
First Name(4): Al
Last Name(4): Jamerncy
Enrollments(4): 1
PL/SQL procedure successfully completed.
LAB 16.3
Lab 16.3 Exercises
377
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
▼
TRY IT YOURSELF
In this chapter, you’ve learned about various types of records, nested records, and collections of records.
Here are some projects that will help you test the depth of your understanding:
1) Create an associative array with the element type of a user-defined record.This record should
contain the first name, last name, and total number of courses that a particular instructor teaches.
Display the records of the associative array on the screen.
2) Modify the script you just created. Instead of using an associative array, use a nested table.
3) Modify the script you just created. Instead of using a nested table, use a varray.
4) Create a user-defined record with four fields: course_no, description, cost, and
prerequisite_rec.The last field, prerequisite_rec, should be a user-defined record
with three fields: prereq_no, prereq_desc, and prereq_cost. For any ten courses that
have a prerequisite course, populate the user-defined record with all the corresponding data, and
display its information on the screen.
The projects in this section are meant to have you use all the skills you have acquired throughout this
chapter.The answers to these projects can be found in Appendix D and on this book’s companion Web
site.Visit the Web site periodically to share and discuss your answers.
378
Try it Yourself
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
CHAPTER 17
Native Dynamic SQL
CHAPTER OBJECTIVES
In this chapter, you will learn about
.
EXECUTE IMMEDIATE statements
.
OPEN-FOR, FETCH, and CLOSE statements
Generally, PL/SQL applications perform a specific task and manipulate a static
set of tables. For example, a stored procedure might accept a student ID and
return the student’s first and last names. In such a procedure, a SELECT state-
ment is known in advance and is compiled as part of the procedure. Such
SELECT statements are called static because they do not change from execution
to execution.
Now, consider a different type of PL/SQL application in which SQL statements
are built on the fly, based on a set of parameters specified at runtime. For
example, an application might need to build various reports based on SQL state-
ments where table and column names are not known in advance, or the sorting
and grouping of data are specified by a user requesting a report. Similarly,
another application might need to create or drop tables or other database objects
based on the action specified by a user at runtime. Because these SQL statements
are generated on the fly and might change from time to time, they are called
dynamic.
PL/SQL has a feature called native dynamic SQL (dynamic SQL for short) that
helps you build applications similar to those just described. The use of dynamic
SQL makes such applications flexible, versatile, and concise because it eliminates
the need for complicated programming approaches. Native dynamic SQL is more
convenient to use than the Oracle-supplied package DBMS_SQL, which has
similar functionality. In this chapter you will learn how to create and use
dynamic SQL.
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
LAB 17.1
EXECUTE IMMEDIATE
Statements
LAB OBJECTIVE
After completing this lab, you will be able to
.
Use the EXECUTE IMMEDIATE statement
Generally, dynamic SQL statements are built by your program and are stored as character strings
based on the parameters specified at runtime. These strings must contain valid SQL statements
or PL/SQL code. Consider the following dynamic SQL statement:
FOR EXAMPLE
'SELECT first_name, last_name FROM student WHERE student_id =
:student_id'
This SELECT statement returns a student’s first and last name for a given student ID. The value
of the student ID is not known in advance and is specified with the help of a bind argument,
:student_id. The bind argument is a placeholder for an undeclared identifier, and its name
must be prefixed by a colon. As a result, PL/SQL does not differentiate between the following
statements:
'SELECT first_name, last_name FROM student WHERE student_id =
:student_id'
'SELECT first_name, last_name FROM student WHERE student_id = :id'
To process dynamic SQL statements, you use EXECUTE IMMEDIATE or OPEN-FOR, FETCH,
and CLOSE statements. EXECUTE IMMEDIATE is used for single-row SELECT statements, all
DML statements, and DDL statements. OPEN-FOR, FETCH, and CLOSE statements are used
for multirow SELECTs and reference cursors.
BY THE WAY
To improve the performance of dynamic SQL statements you can also use BULK EXECUTE IMMEDI-
ATE, BULK FETCH, FORALL, and COLLECT INTO statements. However, these statements are outside the
scope of this book and therefore are not covered.You can find detailed explanations and examples
of their usage in the online Oracle help.
LAB 17.1
380
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
THE EXECUTE IMMEDIATE STATEMENT
The EXECUTE IMMEDIATE statement parses a dynamic statement or a PL/SQL block for imme-
diate execution. Its structure is as follows (the reserved words and phrases in square brackets
are optional):
EXECUTE IMMEDIATE
dynamic_SQL_string
[INTO
defined_variable1
,
defined_variable2
, ]
[USING [IN | OUT | IN OUT]
bind_argument1
,
bind_argument2
,
][{RETURNING | RETURN}
field1
,
field2
, INTO
bind_argument1
,
bind_argument2
, ]
dynamic_SQL_string
is a string that contains a valid SQL statement or a PL/SQL block.
The INTO clause contains the list of predefined variables that hold values returned by the
SELECT statement. This clause is used when a dynamic SQL statement returns a single row
similar to a static SELECT INTO statement. Next, the USING clause contains a list of bind argu-
ments whose values are passed to the dynamic SQL statement or PL/SQL block. IN, OUT, and
IN OUT are modes for bind arguments. If no mode is specified, all bind arguments listed in the
USING clause are in IN mode. Finally, the RETURNING INTO or RETURN clause contains a list
of bind arguments that store values returned by the dynamic SQL statement or PL/SQL block.
Similar to the USING clause, the RETURNING INTO clause may also contain various argument
modes; however, if no mode is specified, all bind arguments are in OUT mode.
DID YOU KNOW?
When an EXECUTE IMMEDIATE statement contains both USING and RETURNING INTO clauses, the
USING clause may specify only IN arguments.
FOR EXAMPLE
DECLARE
sql_stmt VARCHAR2(100);
plsql_block VARCHAR2(300);
v_zip VARCHAR2(5) := '11106';
v_total_students NUMBER;
v_new_zip VARCHAR2(5);
v_student_id NUMBER := 151;
BEGIN
Create table MY_STUDENT
sql_stmt := 'CREATE TABLE my_student '||
'AS SELECT * FROM student WHERE zip = '||v_zip;
EXECUTE IMMEDIATE sql_stmt;
Select total number of records from MY_STUDENT table
and display results on the screen
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM my_student'
INTO v_total_students;
DBMS_OUTPUT.PUT_LINE ('Students added: '||v_total_students);
LAB 17.1
EXECUTE IMMEDIATE Statements
381
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
[...]... procedures Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark This page intentionally left blank Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark CHAPTER 18 Bulk SQL CHAPTER OBJECTIVES In this chapter, you will learn about The FORALL statement The BULK COLLECT clause I n Chapter 1, PL/SQL Concepts,” you learned that the PL/SQL engine sends SQL statements... the dynamic SQL statement used by the previous version (ch17_1b.sql) sql_stmt := 'SELECT a.first_name, a.last_name, a.street_address'|| ' ,b.city, b.state, b.zip' || Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark Lab 17.1 Exercises LAB 17.1 391 ' FROM student a, zipcode b' ' WHERE a.zip = b.zip' ' AND student_id = :1'; || || has been replaced by sql_stmt := 'SELECT a.first_name,... separate the GROUP BY clause This step is necessary because after the strings are concatenated, the resulting SELECT statement looks like this: SELECT zip, COUNT(*) total FROM student GROUP BY zip If no space is added after the STUDENT table, the resulting SELECT statement SELECT zip, COUNT(*) total FROM studentGROUP BY zip causes this error: ERROR: ORA-00933: SQL command not properly ended PL/SQL procedure... a string variable to hold a dynamic SQL statement, and two variables, v_zip and v_total, to hold data returned by the cursor Finally, you define a counter variable so that only the first ten rows returned by the cursor are displayed on the screen Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark Lab 17.2 Exercises LAB 17.2 397 In the executable portion of the script, you... PL/SQL procedure successfully completed Enter value for sv_table_name: instructor old 10: v_table_name VARCHAR2(20) := '&sv_table_name'; new 10: v_table_name VARCHAR2(20) := 'instructor'; Totals from instructor table Zip code: 10005 Total: 1 Zip code: 10015 Total: 3 Zip code: 10025 Total: 4 Zip code: 10035 Total: 1 PL/SQL procedure successfully completed Please purchase PDF Split-Merge on www.verypdf.com... a PL/SQL block is terminated by a slash: FOR EXAMPLE DECLARE plsql_block VARCHAR2(300); BEGIN Select current date and display it on the screen plsql_block := 'DECLARE ' || ' v_date DATE; ' || 'BEGIN ' || ' SELECT SYSDATE INTO v_date FROM DUAL; '|| ' DBMS_OUTPUT.PUT_LINE (TO_CHAR(v_date, ''DD-MON-YYYY''));'|| 'END;' ; EXECUTE IMMEDIATE plsql_block; END; Please purchase PDF Split-Merge on www.verypdf.com... variables TYPE row_num_type IS TABLE OF NUMBER INDEX BY PLS_INTEGER; TYPE row_text_type IS TABLE OF VARCHAR2(10) INDEX BY PLS_INTEGER; row_num_tab row_num_type; row_text_tab row_text_type; v_total NUMBER; BEGIN Populate collections FOR i IN 1 10 LOOP row_num_tab(i) := i; row_text_tab(i) := 'row '||i; END LOOP; Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark LAB 18.1 The FORALL... TABLE test; DECLARE Define collection types and variables TYPE row_num_type IS TABLE OF NUMBER INDEX BY PLS_INTEGER; TYPE row_text_type IS TABLE OF VARCHAR2(10) INDEX BY PLS_INTEGER; row_num_tab row_num_type; row_text_tab row_text_type; v_total NUMBER; Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark The FORALL Statement LAB 18.1 407 v_start_time INTEGER; v_end_time INTEGER;... v_start_time)); COMMIT; END; To calculate execution times of the FOR loop and the FORALL statement, you employ the GET_TIME function from the DBMS_UTILITY package that is owned by the Oracle user SYS Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark ... v_last_name These variables contain results returned by the SELECT statement The USING clause contains the variable v_student_id, which is used to pass a value to the SELECT statement at runtime Finally, two DBMS_OUTPUT.PUT_LINE statements are used to display the results of the SELECT statement on the screen Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark LAB 17.1 Lab 17.1 . Tucker
Names(6): Mithane
PL/SQL procedure successfully completed.
LAB 16.2
372
Lab 16.2 Exercises
Please purchase PDF Split-Merge on www.verypdf.com to remove. Jamerncy
Enrollments(4): 1
PL/SQL procedure successfully completed.
LAB 16.3
Lab 16.3 Exercises
377
Please purchase PDF Split-Merge on www.verypdf.com to remove