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
287,46 KB
Nội dung
a pointer to the query work area that stores the result set. You can declare a cursor variable on
the client side, open and fetch from it on the server side, and then continue to fetch from it on
the client side.
Cursor variables differ from cursors in the same way that constants differ from variables. A
cursor is static; a cursor variable is dynamic. In PL/SQL a cursor variable has a REF CURSOR
datatype, where REF stands for reference and CURSOR stands for the class of the object. You
will now learn the syntax for declaring and using a cursor variable.
To create a cursor variable, first you need to define a REF CURSOR type, and then you declare
a variable of that type.
Before you declare the REF CURSOR of a strong type, you must declare a record that has the
datatypes of the result set of the SELECT statement you plan to use (note that this is not neces-
sary for a weak REF CURSOR).
FOR EXAMPLE
TYPE inst_city_type IS RECORD
(first_name instructor.first_name%TYPE;
last_name instructor.last_name%TYPE;
city zipcode.city%TYPE;
state zipcode.state%TYPE)
Second, you must declare a composite datatype for the cursor variable that is of the type REF
CURSOR. The syntax is as follows:
TYPE
ref_type_name
is REF CURSOR [RETURN
return_type
];
ref_type_name
is a type specified in subsequent declarations.
return_type
is a record
type for a strong cursor; a weak cursor does not have a specific return type but can handle any
combination of data items in a SELECT statement. The REF CURSOR keyword indicates that
the new type will be a pointer to the defined type.
return_type
indicates the type of SELECT
list that the cursor variable eventually returns. The return type must be a record type.
FOR EXAMPLE
TYPE inst_city_cur IS REF CURSOR RETURN inst_city_type;
A cursor variable can be strong (restrictive) or weak (nonrestrictive). A strong cursor variable is
a REF CURSOR type definition that specifies a
return_type
; a weak definition does not.
PL/SQL enables you to associate a strong type with type-comparable queries only, whereas a
weak type can be associated with any query. This makes a strong cursor variable less error-prone
but weak REF CURSOR types more flexible.
LAB 21.2
472
Cursor Variables
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
These are the key steps for handling a cursor variable:
1. Define and declare the cursor variable.
Open the cursor variable. Associate the cursor variable with a multirow SELECT state-
ment, execute the query, and identify the result set. An OPEN FOR statement can open
the same cursor variable for different queries. You do not need to close a cursor variable
before reopening it. Keep in mind that when you reopen a cursor variable for a different
query, the previous query is lost. Good programming technique would be to close the
cursor variables before reopening them later in the program.
2. Fetch rows from the result set.
Retrieve rows from the result set one at a time. Note that the return type of the cursor
variable must be compatible with the variable named in the INTO clause of the FETCH
statement.
The FETCH statement retrieves rows from the result set one at a time. PL/SQL verifies that
the return type of the cursor variable is compatible with the INTO clause of the FETCH
statement. For each query column value returned, the INTO clause must have a type-
comparable variable. Also, the number of query column values must equal the number of
variables. In case of a mismatch in number or type, the error occurs at compile time for
strongly typed cursor variables and at runtime for weakly typed cursor variables.
3. Close the cursor variable.
The following is a complete example showing the use of a cursor variable in a package.
FOR EXAMPLE
ch21_9a.sql
CREATE OR REPLACE PACKAGE course_pkg AS
TYPE course_rec_typ IS RECORD
(first_name student.first_name%TYPE,
last_name student.last_name%TYPE,
course_no course.course_no%TYPE,
description course.description%TYPE,
section_no section.section_no%TYPE
);
TYPE course_cur IS REF CURSOR RETURN course_rec_typ;
PROCEDURE get_course_list
(p_student_id NUMBER ,
p_instructor_id NUMBER ,
course_list_cv IN OUT course_cur);
END course_pkg;
/
CREATE OR REPLACE PACKAGE BODY course_pkg AS
PROCEDURE get_course_list
LAB 21.2
Cursor Variables
473
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
FOR EXAMPLE (continued)
(p_student_id NUMBER ,
p_instructor_id NUMBER ,
course_list_cv IN OUT course_cur)
IS
BEGIN
IF p_student_id IS NULL AND p_instructor_id
IS NULL THEN
OPEN course_list_cv FOR
SELECT 'Please choose a student-' First_name,
'instructor combination' Last_name,
NULL course_no,
NULL description,
NULL section_no
FROM dual;
ELSIF p_student_id IS NULL THEN
OPEN course_list_cv FOR
SELECT s.first_name first_name,
s.last_name last_name,
c.course_no course_no,
c.description description,
se.section_no section_no
FROM instructor i, student s,
section se, course c, enrollment e
WHERE i.instructor_id = p_instructor_id
AND i.instructor_id = se.instructor_id
AND se.course_no = c.course_no
AND e.student_id = s.student_id
AND e.section_id = se.section_id
ORDER BY c.course_no, se.section_no;
ELSIF p_instructor_id IS NULL THEN
OPEN course_list_cv FOR
SELECT i.first_name first_name,
i.last_name last_name,
c.course_no course_no,
c.description description,
se.section_no section_no
FROM instructor i, student s,
section se, course c, enrollment e
WHERE s.student_id = p_student_id
AND i.instructor_id = se.instructor_id
AND se.course_no = c.course_no
AND e.student_id = s.student_id
AND e.section_id = se.section_id
ORDER BY c.course_no, se.section_no;
END IF;
END get_course_list;
END course_pkg;
LAB 21.2
474
Cursor Variables
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
▼
You can pass query result sets between PL/SQL stored subprograms and various clients. This
works because PL/SQL and its clients share a pointer to the query work area identifying the
result set. This can be done in a client program such as SQL*Plus by defining a host variable
with a datatype of REF CURSOR to hold the query result generated from a REF CURSOR in a
stored program. To see what is being stored in the SQL*Plus variable, use the SQL*Plus PRINT
command. Optionally you can have the SQL*Plus command SET AUTOPRINT ON to display
the query results automatically.
LAB 21.2 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.
21.2.1 Make Use of Cursor Variables
A) Take a look at the preceding example, script ch21_9a.sql, and explain why the package has two
different TYPE declarations. Also explain how the procedure get_course_list uses the
cursor variable.
ANSWER: In script ch21_9a.sql, the first TYPE declaration is for the record type course_rec_
type
.This record type is declared to define the result set of the SELECT statements that will be
used for the cursor variable.When data items in a record do not match a single table, it is neces-
sary to create a record type.The second TYPE declaration is for the cursor variable, also known as
REF CURSOR.The variable has the name course_cur, and it is declared as a strong cursor,
meaning that it can be used for only a single record type.The record type is course_rec_
type
.The procedure get_course_list in the course_pkg is made so that it can return
a cursor variable that holds three different result sets. Each result set is of the same record type.
The first type is for when both IN parameters of student ID and instructor ID are null.This
produces a result set that is a message, Please choose a student-instructor
combination.
The next way the procedure runs is if the instructor_id is passed in
but the student_id is null. (Note that the logic of the procedure is a reverse negative.
Saying in the second clause of the IF statement p_student_id IS NULL means when the
instructor_id is passed in.) This runs a SELECT statement to populate the cursor variable
that holds a list of all the courses this instructor teaches and the students enrolled in these
classes.The last way this can run is for a student_id and no instructor_id.This
produces a result set of all the courses the student is enrolled in and the instructors for each
section. Also be aware that after the cursor variable is opened, it is never closed until you specifi-
cally close it.
B) Create a SQL*Plus variable that is a cursor variable type.
ANSWER:
SQL> VARIABLE course_cv REFCURSOR
C) Execute the procedure course_pkg.get_course_list, with three different types of vari-
able combinations to show the three possible result sets. After you execute the procedure, display
the values of the SQL*Plus variable you declared in question A).
ANSWER: There are three ways to execute this procedure.The first way is to pass a student ID
but not an instructor ID:
SQL> exec course_pkg.get_course_list(102, NULL, :course_cv);
PL/SQL procedure successfully completed.
LAB 21.2
Lab 21.2 Exercises
475
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
SQL> print course_cv
FIRST_NAME LAST_NAME COURSE_NO DESCRIPTION SECTION_NO
Charles Lowry 25 Intro to Programming 2
Nina Schorin 25 Intro to Programming 5
The next method is to pass an instructor ID but not a student ID:
SQL> exec course_pkg.get_course_list(NULL, 102, :course_cv);
PL/SQL procedure successfully completed.
SQL> print course_cv
FIRST_NAME LAST_NAME COURSE_NO DESCRIPTION SECTION_NO
Jeff Runyan 10 Technology Concepts 2
Dawn Dennis 25 Intro to Programming 4
May Jodoin 25 Intro to Programming 4
Jim Joas 25 Intro to Programming 4
Arun Griffen 25 Intro to Programming 4
Alfred Hutheesing 25 Intro to Programming 4
Lula Oates 100 Hands-On Windows 1
Regina Bose 100 Hands-On Windows 1
Jenny Goldsmith 100 Hands-On Windows 1
Roger Snow 100 Hands-On Windows 1
Rommel Frost 100 Hands-On Windows 1
Debra Boyce 100 Hands-On Windows 1
Janet Jung 120 Intro to Java Programming 4
John Smith 124 Advanced Java Programming 1
Charles Caro 124 Advanced Java Programming 1
Sharon Thompson 124 Advanced Java Programming 1
Evan Fielding 124 Advanced Java Programming 1
Ronald Tangaribuan 124 Advanced Java Programming 1
N Kuehn 146 Java for C/C++ Programmers 2
Derrick Baltazar 146 Java for C/C++ Programmers 2
Angela Torres 240 Intro to the Basic Language 2
The last method is to pass neither the student ID nor the instructor ID:
SQL> exec course_pkg.get_course_list(NULL, NULL, :course_cv);
PL/SQL procedure successfully completed.
SQL> print course_cv
FIRST_NAME LAST_NAME C DESCRIPTION S
-
Please choose a student-instructor combination
LAB 21.2
476
Lab 21.2 Exercises
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
D) Create another package called student_info_pkg that has a single procedure called
get_student_info.The get_student_info package will have three parameters.The
first is student_id, the second is a number called p_choice, and the last is a weak cursor
variable. p_choice indicates what information about the student will be delivered. If it is 1,
return the information about the student from the STUDENT table. If it is 2, list all the courses the
student is enrolled in, with the names of the students who are enrolled in the same section as the
student with the student_id that was passed in. If it is 3, return the instructor name for that
student, with the information about the courses the student is enrolled in.
ANSWER:
ch21_10a.sql
CREATE OR REPLACE PACKAGE student_info_pkg AS
TYPE student_details IS REF CURSOR;
PROCEDURE get_student_info
(p_student_id NUMBER ,
p_choice NUMBER ,
details_cv IN OUT student_details);
END student_info_pkg;
/
CREATE OR REPLACE PACKAGE BODY student_info_pkg AS
PROCEDURE get_student_info
(p_student_id NUMBER ,
p_choice NUMBER ,
details_cv IN OUT student_details)
IS
BEGIN
IF p_choice = 1 THEN
OPEN details_cv FOR
SELECT s.first_name first_name,
s.last_name last_name,
s.street_address address,
z.city city,
z.state state,
z.zip zip
FROM student s, zipcode z
WHERE s.student_id = p_student_id
AND z.zip = s.zip;
ELSIF p_choice = 2 THEN
OPEN details_cv FOR
SELECT c.course_no course_no,
c.description description,
se.section_no section_no,
s.first_name first_name,
s.last_name last_name
FROM student s, section se,
course c, enrollment e
WHERE se.course_no = c.course_no
AND e.student_id = s.student_id
AND e.section_id = se.section_id
LAB 21.2
Lab 21.2 Exercises
477
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
AND se.section_id in (SELECT e.section_id
FROM student s,
enrollment e
WHERE s.student_id =
p_student_id
AND s.student_id =
e.student_id)
ORDER BY c.course_no;
ELSIF p_choice = 3 THEN
OPEN details_cv FOR
SELECT i.first_name first_name,
i.last_name last_name,
c.course_no course_no,
c.description description,
se.section_no section_no
FROM instructor i, student s,
section se, course c, enrollment e
WHERE s.student_id = p_student_id
AND i.instructor_id = se.instructor_id
AND se.course_no = c.course_no
AND e.student_id = s.student_id
AND e.section_id = se.section_id
ORDER BY c.course_no, se.section_no;
END IF;
END get_student_info;
END student_info_pkg;
E)
Run the get_student_info procedure in SQL*Plus, and display the results.
ANSWER:
SQL> VARIABLE student_cv REFCURSOR
SQL> execute student_info_pkg.GET_STUDENT_INFO
(102, 1, :student_cv);
PL/SQL procedure successfully completed.
SQL> print student_cv
FIRST_ LAST_NAM ADDRESS CITY ST ZIP
Fred Crocitto 101-09 120th St. Richmond Hill NY 11419
SQL> execute student_info_pkg.GET_STUDENT_INFO
(102, 2, :student_cv);
PL/SQL procedure successfully completed.
SQL> print student_cv
COURSE_NO DESCRIPTION SECTION_NO FIRST_NAME LAST_NAME
25 Intro to Programming 2 Fred Crocitto
25 Intro to Programming 2 Judy Sethi
25 Intro to Programming 2 Jenny Goldsmith
LAB 21.2
478
Lab 21.2 Exercises
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
25 Intro to Programming 2 Barbara Robichaud
25 Intro to Programming 2 Jeffrey Citron
25 Intro to Programming 2 George Kocka
25 Intro to Programming 5 Fred Crocitto
25 Intro to Programming 5 Hazel Lasseter
25 Intro to Programming 5 James Miller
25 Intro to Programming 5 Regina Gates
25 Intro to Programming 5 Arlyne Sheppard
25 Intro to Programming 5 Thomas Edwards
25 Intro to Programming 5 Sylvia Perrin
25 Intro to Programming 5 M. Diokno
25 Intro to Programming 5 Edgar Moffat
25 Intro to Programming 5 Bessie Heedles
25 Intro to Programming 5 Walter Boremmann
25 Intro to Programming 5 Lorrane Velasco
SQL> execute student_info_pkg.GET_STUDENT_INFO
(214, 3, :student_cv);
PL/SQL procedure successfully completed.
SQL> print student_cv
FIRST_NAME LAST_NAME COURSE_NO DESCRIPTION SECTION_NO
Marilyn Frantzen 120 Intro to Java Programming 1
Fernand Hanks 122 Intermediate Java Programming 5
Gary Pertez 130 Intro to Unix 2
Marilyn Frantzen 145 Internet Protocols 1
RULES FOR USING CURSOR VARIABLES
.
Cursor variables cannot be defined in a package specification.
.
You cannot use cursor variables with remote subprograms on another server, so you cannot
pass cursor variables to a procedure that is called through a database link.
.
Do not use FOR UPDATE with OPEN FOR in processing a cursor variable.
.
You cannot use comparison operators to test cursor variables for equality, inequality, or nullity.
.
A cursor variable cannot be assigned a null value.
.
A REF CURSOR type cannot be used in a CREATE TABLE or VIEW statement, because there is no
equivalent datatype for a database column.
.
A stored procedure that uses a cursor variable can be used only as a query block data source;
it cannot be used for a DML block data source. Using a REF CURSOR is ideal for queries that
are dependent only on variations in SQL statements, not PL/SQL.
.
You cannot store cursor variables in an associative array, nested table, or varray.
.
If you pass a host cursor variable to PL/SQL, you cannot fetch from it on the server side unless
you also open it there on the same server call.
LAB 21.2
Lab 21.2 Exercises
479
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
▼
LAB 21.3
Extending the Package
LAB OBJECTIVE
After completing this lab, you will be able to
.
Extend the package
In this lab you use previously learned concepts to extend the packages you have created and
create a new one. Only through extensive exercises will you become more comfortable with
programming in PL/SQL. It is very important when writing your PL/SQL code that you carefully
consider all aspects of the business requirements. A good rule of thumb is to think ahead and
write your code in reusable components so that it will be easy to extend and maintain your
PL/SQL code.
LAB 21.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.
21.3.1 Extend the Package
A) Create a new package specification called manage_grades. This package will perform a
number of calculations on grades and will need two package level cursors.The first one is for
grade types and will be called c_grade_type. It will have an IN parameter of a section ID. It
will list all the grade types (such as quiz or homework) for a given section that are needed to
calculate a student’s grade in that section. The return items from the cursor will be the grade type
code, the number of that grade type for this section, the percentage of the final grade, and the
drop-lowest indicator. First, write a SELECT statement to make sure that you have the correct
items, and then write this as a cursor in the package.
ANSWER:
ch21_11a.sql
CREATE OR REPLACE PACKAGE MANAGE_GRADES AS
Cursor to loop through all grade types for a given section.
CURSOR c_grade_type
(pc_section_id section.section_id%TYPE,
PC_student_ID student.student_id%TYPE)
IS
SELECT GRADE_TYPE_CODE,
NUMBER_PER_SECTION,
LAB 21.3
480
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
PERCENT_OF_FINAL_GRADE,
DROP_LOWEST
FROM grade_Type_weight
WHERE section_id = pc_section_id
AND section_id IN (SELECT section_id
FROM grade
WHERE student_id = pc_student_id);
END MANAGE_GRADES;
B)
Add a second package cursor to the package Manage_Grades called c_grades. This cursor
will take a grade type code, student ID, and section ID and return all the grades for that student
for that section of that grade type. For example, if Alice were registered in “Intro to Java
Programming,” this cursor could be used to gather all her quiz grades.
ANSWER:
ch21_11b.sql
CREATE OR REPLACE PACKAGE MANAGE_GRADES AS
Cursor to loop through all grade types for a given section.
CURSOR c_grade_type
(pc_section_id section.section_id%TYPE,
PC_student_ID student.student_id%TYPE)
IS
SELECT GRADE_TYPE_CODE,
NUMBER_PER_SECTION,
PERCENT_OF_FINAL_GRADE,
DROP_LOWEST
FROM grade_Type_weight
WHERE section_id = pc_section_id
AND section_id IN (SELECT section_id
FROM grade
WHERE student_id = pc_student_id);
Cursor to loop through all grades for a given student
in a given section.
CURSOR c_grades
(p_grade_type_code
grade_Type_weight.grade_type_code%TYPE,
pc_student_id student.student_id%TYPE,
pc_section_id section.section_id%TYPE) IS
SELECT grade_type_code,grade_code_occurrence,
numeric_grade
FROM grade
WHERE student_id = pc_student_id
AND section_id = pc_section_id
AND grade_type_code = p_grade_type_code;
END MANAGE_GRADES;
C)
Add a procedure to this package specification called final_grade. This function will have
parameters of student ID and section ID. It will return a number that is that student’s final grade in
that section, as well as an exit code.You are adding an exit code instead of raising exceptions
because this makes the procedure more flexible and allows the calling program to choose how to
proceed depending on what the error code is.
LAB 21.3
Lab 21.3 Exercises
481
Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark.
[...]... on your particular installation, so ask your DBA The file will be found under the directory that your Oracle server is installed in This directory is refered to as the ORACLE_ HOME The subdirectory would be as follows: ( $ORACLE_ HOME/rdbms/admin/utldtree.sql) Second, fill the DEPTREE e_temptab table by running DEPTREE_FILL Example: SQL> exec DEPTREE_FILL('TABLE', USER, 'COURSE') Finally, look at the... grade WHERE section_id = (SELECT section_id FROM section WHERE course_no= p_course_no AND section_no = p_section_no) AND grade_type_code = p_grade_type_code ORDER BY numeric_grade; TYPE t_grade_type IS TABLE OF c_work_grade%ROWTYPE INDEX BY BINARY_INTEGER; t_grade t_grade_type; END MANAGE_GRADES; H) Add a function to the manage_grades package specification called median_grade that takes in a course... STATUS FROM USER_OBJECTS WHERE OBJECT_TYPE IN ('FUNCTION', 'PROCEDURE', 'PACKAGE', 'PACKAGE_BODY') ORDER BY OBJECT_TYPE; B) Type the following script into a text file, and run the script in SQL*Plus It creates the function scode_at_line Explain the purpose of this function What is accomplished by running it? When does a developer find it useful? ch22_1a.sql CREATE OR REPLACE FUNCTION scode_at_line... v_temp FROM course; END; Now enter the following: SHO ERR What do you see? ANSWER: Errors for PROCEDURE FORCE_ERROR: LINE/COL ERROR -4/4 PL/SQL: SQL Statement ignored 5/9 PLS-00201: identifier 'V_TEMP' must be declared 6/4 PL/SQL: ORA-00904: : invalid identifier E) How can you retrieve information from the USER_ERRORS view? ANSWER: SELECT line||'/'||position “LINE/COL”, TEXT “ERROR”... this student in this section E: A general computation error occurred (exception when_others) Having this type of exit code allows the procedure to compute final grades when it can If an Oracle error is somehow raised by some of the grades, the calling program can still proceed with the grades that have been computed To process the calcuation, you need a number of variables to hold temporary values during... STUDENT.COURSE_PKG 10 rows selected 22.1.2 Enforce the Purity Level with the RESTRICT_REFERENCES Pragma The RESTRICT_REFERENCES pragma is now used for backward compatibility only In Oracle Database versions prior to 8.1.5 (Oracle 8i), programmers used the pragma RESTRICT_REFERENCES to assert a Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark Lab 22.1 Exercises LAB 22.1 501... ANSWER: At first glance you might think you would see a list of student_ids, with the total cost of the courses they took But instead you may get the following error (depending on the version of Oracle; in Oracle 11g you do not get this error): ERROR at line 1: ORA-06571: Function TOTAL_COST_FOR_STUDENT does not guarantee not to update database Although functions can be used in a SELECT statement,... the function returns a valid Oracle database type A user-defined function may select from database tables or call other procedures or functions, whether stand-alone or packaged When a function is used in a SELECT statement, it may not modify data in any database table with an INSERT, UPDATE, or DELETE statement, or read or write package variables across user sessions The Oracle server automatically... type_in is NULL The default values are designed to make this function as easy as possible to use Please purchase PDF Split-Merge on www.verypdf.com to remove this watermark LAB 22.1 Lab 22.1 Exercises 498 BY THE WAY The output from a call to SHOW ERRORS in SQL*Plus displays the line number on which an error occurred, but the line number doesn’t correspond to the line in your text file Instead, it relates... student.student_id%TYPE := 102; Enter value for sv_section_id: 86 old 3: v_section_id section.section_id%TYPE := &sv_section_id; new 3: v_section_id section.section_id%TYPE := 86; The Final Grade is 89 The Exit Code is S PL/SQL procedure successfully completed G) Add a function to the manage_grades package specification called median_grade that takes in a course number (p_course_number), a section number (p_section_number), . watermark.
▼
You can pass query result sets between PL/SQL stored subprograms and various clients. This
works because PL/SQL and its clients share a pointer to the. statements, not PL/SQL.
.
You cannot store cursor variables in an associative array, nested table, or varray.
.
If you pass a host cursor variable to PL/SQL, you