Você está na página 1de 5

Processing Queries with PL/SQL

Processing a SQL query with PL/SQL is like processing files with other languages. For example, a Perl program opens a file, reads the file contents, processes each line, then closes the file. In the same way, a PL/SQL program issues a query and processes the rows from the result set as shown in Example 15.
Example 15 Processing Query Results in a LOOP BEGIN FOR someone IN (SELECT * FROM employees WHERE employee_id < 120 ) LOOP DBMS_OUTPUT.PUT_LINE('First name = ' || someone.first_name || ', Last name = ' || someone.last_name); END LOOP; END; /

You can use a simple loop like the one shown here, or you can control the process precisely by using individual statements to perform the query, retrieve data, and finish processing.

Declaring PL/SQL Subprograms


Subprograms are named PL/SQL blocks that can be called with a set of parameters. PL/SQL has two types of subprograms: procedures and functions. The following is an example of a declaration of a PL/SQL procedure:
DECLARE in_string VARCHAR2(100) := 'This is my test string.'; out_string VARCHAR2(200); PROCEDURE double ( original IN VARCHAR2, new_string OUT VARCHAR2 ) AS BEGIN new_string := original || original; END;

For example of a subprogram declaration in a package, see Example 113 on page 1-14. For more information on subprograms, see "What Are Subprograms?" on page 8-1. You can create standalone subprograms with SQL statements that are stored in the database. See Subprograms: Procedures and Functions on page 1-13.

Declaring Datatypes for PL/SQL Variables


As part of the declaration for each PL/SQL variable, you declare its datatype. Usually, this datatype is one of the types shared between PL/SQL and SQL, such as NUMBER or VARCHAR2. For easier maintenance of code that interacts with the database, you can also use the special qualifiers %TYPE and %ROWTYPE to declare variables that hold table columns or table rows. For more information on datatypes, see Chapter 3, "PL/SQL Datatypes".

%TYPE
The %TYPE attribute provides the datatype of a variable or database column. This is particularly useful when declaring variables that will hold database values. For example, assume there is a column named last_name in a table named employees. To declare a variable named v_last_name that has the same datatype as column title, use dot notation and the %TYPE attribute, as follows: v_last_name employees.last_name%TYPE; Understanding the Main Features of PL/SQL
Overview of PL/SQL 1-9

Declaring v_last_name with %TYPE has two advantages. First, you need not know the exact datatype of last_name. Second, if you change the database definition of last_name, perhaps to make it a longer character string, the datatype of v_last_name changes accordingly at run time. For more information on %TYPE, see "Using the %TYPE Attribute" on page 2-10 and "%TYPE Attribute" on page 13-119.

%ROWTYPE
In PL/SQL, records are used to group data. A record consists of a number of related

fields in which data values can be stored. The %ROWTYPE attribute provides a record type that represents a row in a table. The record can store an entire row of data selected from the table or fetched from a cursor or cursor variable. See "Cursors" on page 1-16. Columns in a row and corresponding fields in a record have the same names and datatypes. In the following example, you declare a record named dept_rec. Its fields have the same names and datatypes as the columns in the departments table. DECLARE dept_rec departments%ROWTYPE; -- declare record variable You use dot notation to reference fields, as the following example shows: v_deptid := dept_rec.department_id; If you declare a cursor that retrieves the last name, salary, hire date, and job class of an employee, you can use %ROWTYPE to declare a record that stores the same information as shown in Example 16. When you execute the FETCH statement, the value in the last_name column of the employees table is assigned to the last_name field of employee_rec, the value in the salary column is assigned to the salary field, and so on.
Example 16 Using %ROWTYPE with an Explicit Cursor DECLARE CURSOR c1 IS SELECT last_name, salary, hire_date, job_id FROM employees WHERE employee_id = 120; -- declare record variable that represents a row fetched from the employees table employee_rec c1%ROWTYPE; BEGIN -- open the explicit cursor and use it to fetch data into employee_rec OPEN c1; FETCH c1 INTO employee_rec; DBMS_OUTPUT.PUT_LINE('Employee name: ' || employee_rec.last_name); END; /

For more information on %ROWTYPE, see "Using the %ROWTYPE Attribute" on page 2-11 and "%ROWTYPE Attribute" on page 13-104.

Understanding PL/SQL Control Structures


Control structures are the most important PL/SQL extension to SQL. Not only does PL/SQL let you manipulate Oracle data, it lets you process the data using conditional, iterative, and sequential flow-of-control statements such as IF-THEN-ELSE, CASE, Understanding the Main Features of PL/SQL
1-10 Oracle Database PL/SQL Users Guide and Reference

FOR-LOOP, WHILE-LOOP, EXIT-WHEN, and GOTO. For additional information, see Chapter 4, "Using PL/SQL Control Structures".

Conditional Control
Often, it is necessary to take alternative actions depending on circumstances. The IF-THEN-ELSE statement lets you execute a sequence of statements conditionally. The IF clause checks a condition, the THEN clause defines what to do if the condition is true and the ELSE clause defines what to do if the condition is false or null. Example 17 shows the use of IF-THEN-ELSE to determine the salary raise an employee receives based on the current salary of the employee. To choose among several values or courses of action, you can use CASE constructs. The CASE expression evaluates a condition and returns a value for each case. The case statement evaluates a condition and performs an action, such as an entire PL/SQL block, for each case. See Example 17.
Example 17 Using the IF-THEN_ELSE and CASE Statement for Conditional Control DECLARE jobid employees.job_id%TYPE; empid employees.employee_id%TYPE := 115; sal employees.salary%TYPE;

sal_raise NUMBER(3,2); BEGIN SELECT job_id, salary INTO jobid, sal from employees WHERE employee_id = empid; CASE WHEN jobid = 'PU_CLERK' THEN IF sal < 3000 THEN sal_raise := .12; ELSE sal_raise := .09; END IF; WHEN jobid = 'SH_CLERK' THEN IF sal < 4000 THEN sal_raise := .11; ELSE sal_raise := .08; END IF; WHEN jobid = 'ST_CLERK' THEN IF sal < 3500 THEN sal_raise := .10; ELSE sal_raise := .07; END IF; ELSE BEGIN DBMS_OUTPUT.PUT_LINE('No raise for this job: ' || jobid); END; END CASE; UPDATE employees SET salary = salary + salary * sal_raise WHERE employee_id = empid; COMMIT; END; /

A sequence of statements that uses query results to select alternative actions is common in database applications. Another common sequence inserts or deletes a row only if an associated entry is found in another table. You can bundle these common sequences into a PL/SQL block using conditional logic.

Iterative Control
LOOP statements let you execute a sequence of statements multiple times. You place the keyword LOOP before the first statement in the sequence and the keywords END Understanding the Main Features of PL/SQL
Overview of PL/SQL 1-11

LOOP after the last statement in the sequence. The following example shows the simplest kind of loop, which repeats a sequence of statements continually: LOOP -- sequence of statements END LOOP; The FOR-LOOP statement lets you specify a range of integers, then execute a sequence of statements once for each integer in the range. In Example 18 the loop inserts 100 numbers, square roots, squares, and the sum of squares into a database table:
Example 18 Using the FOR-LOOP CREATE TABLE sqr_root_sum (num NUMBER, sq_root NUMBER(6,2), sqr NUMBER, sum_sqrs NUMBER); DECLARE s PLS_INTEGER; BEGIN FOR i in 1..100 LOOP s := (i * (i + 1) * (2*i +1)) / 6; -- sum of squares INSERT INTO sqr_root_sum VALUES (i, SQRT(i), i*i, s ); END LOOP; END; /

The WHILE-LOOP statement associates a condition with a sequence of statements. Before each iteration of the loop, the condition is evaluated. If the condition is true, the sequence of statements is executed, then control resumes at the top of the loop. If the condition is false or null, the loop is bypassed and control passes to the next statement. In Example 19, you find the first employee who has a salary over $15000 and is

higher in the chain of command than employee 120:


Example 19 Using WHILE-LOOP for Control CREATE TABLE temp (tempid NUMBER(6), tempsal NUMBER(8,2), tempname VARCHAR2(25)); DECLARE sal employees.salary%TYPE := 0; mgr_id employees.manager_id%TYPE; lname employees.last_name%TYPE; starting_empid employees.employee_id%TYPE := 120; BEGIN SELECT manager_id INTO mgr_id FROM employees WHERE employee_id = starting_empid; WHILE sal <= 15000 LOOP -- loop until sal > 15000 SELECT salary, manager_id, last_name INTO sal, mgr_id, lname FROM employees WHERE employee_id = mgr_id; END LOOP; INSERT INTO temp VALUES (NULL, sal, lname); -- insert NULL for tempid COMMIT; EXCEPTION WHEN NO_DATA_FOUND THEN INSERT INTO temp VALUES (NULL, NULL, 'Not found'); -- insert NULLs COMMIT; END; /

The EXIT-WHEN statement lets you complete a loop if further processing is impossible or undesirable. When the EXIT statement is encountered, the condition in the WHEN clause is evaluated. If the condition is true, the loop completes and control passes to Understanding the Main Features of PL/SQL
1-12 Oracle Database PL/SQL Users Guide and Reference

the next statement. In Example 110, the loop completes when the value of total exceeds 25,000:
Example 110 Using the EXIT-WHEN Statement DECLARE total NUMBER(9) := 0; counter NUMBER(6) := 0; BEGIN LOOP counter := counter + 1; total := total + counter * counter; -- exit loop when condition is true EXIT WHEN total > 25000; END LOOP; DBMS_OUTPUT.PUT_LINE('Counter: ' || TO_CHAR(counter) || ' Total: ' || TO_CHAR(total)); END; /

Sequential Control
The GOTO statement lets you branch to a label unconditionally. The label, an undeclared identifier enclosed by double angle brackets, must precede an executable statement or a PL/SQL block. When executed, the GOTO statement transfers control to the labeled statement or block, as shown in Example 111.
Example 111 Using the GOTO Statement DECLARE total NUMBER(9) := 0; counter NUMBER(6) := 0; BEGIN <<calc_total>> counter := counter + 1; total := total + counter * counter; -- branch to print_total label when condition is true IF total > 25000 THEN GOTO print_total; ELSE GOTO calc_total;

END IF; <<print_total>> DBMS_OUTPUT.PUT_LINE('Counter: ' || TO_CHAR(counter) || ' Total: ' || TO_CHAR(total)); END; /

Você também pode gostar