9.1.1 Make Use of Record TypesHere is an example of a record type in an anonymous PL/SQL block. FOR EXAMPLE SET SERVEROUTPUT ON; DECLARE vr_zip ZIPCODE%ROWTYPE; BEGIN SELECT * INTO vr_zip FROM zipcode WHERE rownum < 2; DBMS_OUTPUT.PUT_LINE('City: 'vr_zip.city); DBMS_OUTPUT.PUT_LINE('State: 'vr_zip.state); DBMS_OUTPUT.PUT_LINE('Zip: 'vr_zip.zip); END;
A cursor-based record is based on the list of elements of a predefined cursor.
FOR EXAMPLE DECLARE CURSOR c_student_name IS SELECT first_name, last_name FROM student; vr_student_name c_student_name%ROWTYPE; In the next Lab you will learn how to process an explicit cursor. Afterward you will address record types within that process. 9.1.2 Process an Explicit Cursor
Opening a CursorThe next step in controlling an explicit cursor is to open it. When the Open cursor statement is processed , the following four actions will take place automatically:
The syntax for opening a cursor is OPEN cursor_name;
Fetching Rows in a CursorAfter the cursor has been declared and opened, you can then retrieve data from the cursor. The process of getting the data from the cursor is referred to as fetching the cursor. There are two methods of fetching a cursor, done with the following command: FETCH cursor_name INTO PL/SQL variables; or FETCH cursor_name INTO PL/SQL record; When the cursor is fetched, the following occurs:
FOR EXAMPLE -- ch09_2a.sql SET SERVEROUTPUT ON DECLARE CURSOR c_zip IS SELECT * FROM zipcode; vr_zip c_zip%ROWTYPE; BEGIN OPEN c_zip; LOOP FETCH c_zip INTO vr_zip; EXIT WHEN c_zip%NOTFOUND; DBMS_OUTPUT.PUT_LINE(vr_zip.zip ' 'vr_zip.city' 'vr_zip.state); END LOOP; END; The lines in italics have not yet been covered but are essential for the code to run correctly. They will be explained later in this chapter.
Closing a CursorOnce all of the rows in the cursor have been processed (retrieved), the cursor should be closed. This tells the PL/SQL engine that the program is finished with the cursor, and the resources associated with it can be freed. The syntax for closing the cursor is CLOSE cursor_name;
Next, consider another example. FOR EXAMPLE SET SERVEROUTPUT ON; DECLARE CURSOR c_student_name IS SELECT first_name, last_name FROM student WHERE rownum <= 5; vr_student_name c_student_name%ROWTYPE; BEGIN OPEN c_student_name; LOOP FETCH c_student_name INTO vr_student_name; EXIT WHEN c_student_name%NOTFOUND; DBMS_OUTPUT.PUT_LINE('Student name: ' vr_student_name.first_name' 'vr_student_name.last_name); END LOOP; CLOSE c_student_name; END;
FOR EXAMPLE SET SERVEROUTPUT ON; DECLARE CURSOR c_student_name IS SELECT first_name, last_name FROM student WHERE rownum <= 5; vr_student_name c_student_name%ROWTYPE; BEGIN OPEN c_student_name; LOOP FETCH c_student_name INTO vr_student_name; EXIT WHEN c_student_name%NOTFOUND; END LOOP; CLOSE c_student_name; DBMS_OUTPUT.PUT_LINE('Student name: ' vr_student_name.first_name' 'vr_student_name.last_name); END; A programmer-defined record is based on the record type defined by a programmer. First you declare a record type, and next, you declare a record based on the record type defined in the previous step as follows : type type_name IS RECORD (field_name 1 DATATYPE 1, field_name 2 DATATYPE 2, field_name N DATATYPE N); record_name TYPE_NAME%ROWTYPE; Consider the following code fragment. FOR EXAMPLE SET SERVEROUTPUT ON; DECLARE -- declare user-defined type TYPE instructor_info IS RECORD (instructor_id instructor.instructor_id%TYPE, first_name instructor.first_name%TYPE, last_name instructor.last_name%TYPE, sections NUMBER(1)); -- declare a record based on the type defined above rv_instructor instructor_info; In this code fragment, you define your own type, instructor_info . This type contains four attributes: instructor's ID, first and last names , and number of sections taught by this instructor. Next, you declare a record based on the type just described. As a result, this record has structure similar to the type, instructor_ info . Consider the following example. FOR EXAMPLE SET SERVEROUTPUT ON; DECLARE TYPE instructor_info IS RECORD (first_name instructor.first_name%TYPE, last_name instructor.last_name%TYPE, sections NUMBER); rv_instructor instructor_info; BEGIN SELECT RTRIM(i.first_name), RTRIM(i.last_name), COUNT(*) INTO rv_instructor FROM instructor i, section s WHERE i.instructor_id = s.instructor_id AND i.instructor_id = 102 GROUP BY i.first_name, i.last_name; DBMS_OUTPUT.PUT_LINE('Instructor, ' rv_instructor.first_name' 'rv_instructor.last_name ', teaches 'rv_instructor.sections' section(s)'); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE ('There is no such instructor'); END;
9.1.3 Make Use of Cursor AttributesTable 9.1 lists the attributes of a cursor, which are used to determine the result of a cursor operation when fetched or opened .
Cursor attributes can be used with implicit cursors by using the prefix SQL, for example, SQL%ROWCOUNT. If you use a SELECT INTO syntax in your PL/SQL block, you will be creating an implicit cursor. You can then use these attributes on the implicit cursor. FOR EXAMPLE -- ch09_3a.sql SET SERVEROUTPUT ON DECLARE v_city zipcode.city%type; BEGIN SELECT city INTO v_city FROM zipcode WHERE zip = 07002; IF SQL%ROWCOUNT = 1 THEN DBMS_OUTPUT.PUT_LINE(v_city ' has a ' 'zipcode of 07002'); ELSIF SQL%ROWCOUNT = 0 THEN DBMS_OUTPUT.PUT_LINE('The zipcode 07002 is ' ' not in the database'); ELSE DBMS_OUTPUT.PUT_LINE('Stop harassing me'); END IF; END; Table 9.1. Explicit Cursor Attributes
9.1.4 Put It All TogetherHere is an example of the complete cycle of declaring, opening, fetching, and closing a cursor, including use of cursor attributes. -- ch09_4a.sql 1> DECLARE 2> v_sid student.student_id%TYPE; 3> CURSOR c_student IS 4> SELECT student_id 5> FROM student 6> WHERE student_id < 110; 7> BEGIN 8> OPEN c_student; 9> LOOP 10> FETCH c_student INTO v_sid; 11> EXIT WHEN c_student%NOTFOUND; 12> DBMS_OUTPUT.PUT_LINE('STUDENT ID : 'v_sid); 13> END LOOP; 14> CLOSE c_student; 15> EXCEPTION 16> WHEN OTHERS 17> THEN 18> IF c_student%ISOPEN 19> THEN 20> CLOSE c_student; 21> END IF; 22> END;
|