Rdbms Electronic Text Book Unit5
Rdbms Electronic Text Book Unit5
PART 3
PL/SQL
10
PL/SQL:
A Programming Language
IN THIS CHAPTER . . .
● Data encapsulation.
● Error handling.
ShahCh10v3.qxd 4/16/04 11:59 AM Page 226
● Information hiding.
● Object-oriented programming (OOP).
Before PL/SQL was developed, users embedded SQL statements into hot languages
like C++ and Java. PL/SQL version 1.0 was introduced with Oracle 6.0 in 1991. Ver-
sion 1.0 had very limited capabilities, however, and was far from being a full-fledged
programming language. It was merely used for batch processing.
With versions 2.0, 2.1, and 2.2, the following new features were introduced:
PL/SQL version 8.0, also known as PL/SQL8, came with Oracle8, the “object-
relational” database software. Oracle allows creation of objects that can be accessed
with Java, C++, Object COBOL, and other languages. It also allows objects and re-
lational tables to coexist. The external procedures in Oracle allow you to compile
procedures and store them in the shared library of the operating system—for exam-
ple, an .so file in UNIX or a .dll (Dynamic Linked Library) file in Windows. Oracle’s
library is written in the C language. It also supports LOB (Large Object) data types.
FUNDAMENTALS OF PL/SQL
Reserved Words
The reserved words, or key words, are words provided by the language that have a
specific use in the language. For example, DECLARE, BEGIN, END, IF, WHILE,
EXCEPTION, PROCEDURE, FUNCTION, PACKAGE, and TRIGGER are some
of the reserved words in PL/SQL.
User-Defined Identifiers
It is a good practice to create short and meaningful names. Figure 10-1 shows a
list of valid user-defined identifiers. Figure 10-2 shows a list of invalid user-defined
identifiers along with reasons why they are invalid.
ShahCh10v3.qxd 4/16/04 11:59 AM Page 228
User-Defined Identifiers
Rate_of_pay
Num
A1234567890
Dollars$_and_cents
SS#
Literals
Literals are values that are not represented by user-defined identifiers. Literals are
of three types: numeric, character, and boolean. For example:
In this list of values, ‘25-MAY-00’ looks like a date value, but it is a character string. It
can be converted to date format by using the TO_DATE function. The value ‘’ (two
single quotes having nothing within) is another way of entering the NULL value.
PL/SQL is case sensitive regarding character values within single quotation
marks. The values ‘ORACLE’, ‘Oracle’, and ‘oracle’ are three different values in
PL/SQL. To embed a single quote in a string value, two single quote symbols are
entered—for example, ‘New Year”s Day’.
Numeric values can be entered in scientific notation with the letter E or e.
Boolean values are not enclosed in quotation marks.
1. A declaration section.
2. An executable section.
3. An exception-handling section.
Figure 10-3 shows the use of three sections in a PL/SQL block. Of the three sections
in a PL/SQL block, only the executable section is mandatory. The declaration and ex-
ception-handling sections are optional. The general syntax of an anonymous block is
[ DECLARE
Declaration of constants, variables, cursors, and exceptions ]
BEGIN
Executable PL/SQL and SQL statements
[EXCEPTION
Actions for error conditions ]
END;
Section Use
The DECLARE and EXCEPTION key words are optional, but the BEGIN and END
key words are mandatory. The declarations made within a block are local to the block.
When a block ends, all objects declared within the block cease to exist. A block
is the “scope” of objects declared in that block. When blocks are nested within each
other, the declarations made in the outer block are global to the inner block. The ob-
ject declarations made in the inner block, however, are local to it and cannot be ref-
erenced by the outer block. A basic PL/SQL block can be embedded in any other
PL/SQL block, named or unnamed. Figure 10-4 shows all the blocks available in the
Oracle server environment.
ShahCh10v3.qxd 4/16/04 11:59 AM Page 230
Block Use
COMMENTS
Comments are used to document programs. They are written as part of a program, but
they are not executed. In fact, comments are ignored by the PL/SQL engine. It is a good
programming practice to add comments to a program, because this helps in readability
and debugging of the program. There are two ways to write comments in PL/SQL:
1. To write a single-line comment, two dashes (--) are entered at the begin-
ning of a new line. For example,
- -This is a single-line comment.
/* This is a
multiline comment
that ends here. */
DATA TYPES
Each constant and variable in the program needs a data type. The data type decides
the type of value that can be stored in a variable. PL/SQL has four data types:
1. Scalar.
2. Composite.
3. Reference.
4. LOB.
ShahCh10v3.qxd 4/16/04 11:59 AM Page 231
A scalar data type is not made up of a group of elements. It is atomic in nature. The
composite data types are made up of elements or components. PL/SQL supports
three composite data types—records, tables, and varrays, which are discussed in a
later chapter. The reference data types deal with objects, which are briefly introduced
in Appendix D.
There are four major categories of scalar data types:
1. Character.
2. Number.
3. Boolean.
4. Date.
Character
Variables with a character data type can store text. The text may include letters,
numbers, and special characters. The text in character-type variables can be manipu-
lated with built-in character functions. Character data types include CHAR and
VARCHAR2.
CHAR. The CHAR data type is used for fixed-length string values. The allow-
able string length is between 1 and 32,767. (If you remember, the allowable length in
the Oracle database is only 2000.) If you do not specify a length for the variable, the
default length is one. Get into the habit of specifying length along with the data type
to avoid any errors.
If you are going to declare a variable of the CHAR type in PL/SQL code and
that value is to be inserted into a table’s column, the limitation on database size is
only 2000 characters. You will have to find the substring of that character value to
avoid the error message for inserting a character string longer than the length of the
column.
If you specify a length of 10 and the assigned value is only five characters long,
the value is padded with trailing spaces because of the fixed-length nature of this
data type. The CHAR type is not storage efficient, but it is performance efficient.
padded with spaces. If the values of both variables are compared in a condition for
equality, FALSE will be returned.
Other character data types are LONG (32,760 bytes, shorter than VARCHAR2),
RAW (32,767 bytes), and LONG RAW (32,760 bytes, shorter than RAW). The RAW
data values are neither interpreted nor converted by Oracle.
VARCHAR2 is the most recommended character data type.
Number
PL/SQL has a variety of numeric data types. Whole numbers or integer values can
be handled by following data types:
NUMBER
DEC (fixed-point number)
DECIMAL (fixed-point number)
NUMERIC (fixed-point number)
FLOAT (floating-point number)
REAL (floating-point number)
DOUBLE PRECISION (floating-point number)
You are familiar with the NUMBER type from the Oracle table’s column type.
The NUMBER type can be used for fixed-point or floating-point decimal numbers.
It provides an accuracy of up to 38 decimal places. When using the NUMBER type,
the precision and scale values are provided. The precision of a number is the total
number of significant digits in that number, and the scale is the number of signifi-
cant decimal places. The precision and scale values must be whole-number integers.
For example,
NUMBER(p, s)
Boolean
PL/SQL has a logical data type, Boolean, that is not available in SQL. It is used for
Boolean data TRUE, FALSE, or NULL only. These values are not enclosed in single
quotation marks like character and date values.
Date
The date type is a special data type that stores date and time information. The date
values have a specific format. A user can enter a date in many different formats with
the TO_DATE function, but a date is always stored in standard 7-byte format. A
date stores the following information:
Century
Year
Month
Day
Hour
Minute
Second
The valid date range is from January 1, 4712 B.C., to December 31, 9999 A.D.
The time is stored as the number of seconds past midnight. If the user leaves out the
time portion of the data, it defaults to midnight (12:00:00 A.M.).
Various DATE functions are available for date calculations. For example, the
SYSDATE function is used to return the system’s current date.
NLS
The National Language Support (NLS) data type is for character sets in which mul-
tiple bytes are used for character representation. NCHAR and NVARCHAR2 are
examples of NLS data types.
LOB
Like Oracle9i, PL/SQL also supports Large Object (LOB) data types to store large
values of character, raw, or binary data. The LOB types allow up to 4 gigabytes of
data. LOB variables can be given one of the following data types:
● The BLOB type contains a pointer to the large binary object inside the
database.
● The CLOB type contains a pointer to a large block of single-byte character
data of fixed width.
ShahCh10v3.qxd 4/16/04 11:59 AM Page 234
VARIABLE DECLARATION
A scalar variable or a constant is declared with a data type and an initial value assign-
ment. The declarations are done in the DECLARE section of the program block. The
initial value assignment for a variable is optional unless it has a NOT NULL con-
straint. The constants and NOT NULL type variables must be initialized. The general
syntax is
DECLARE
identifiername [CONSTANT] datatype [NOT NULL] [:= | DEFAULT expression];
DECLARE
v_number NUMBER(2);
v_count NUMBER(1) := 1;
v_state VARCHAR2(2) DEFAULT ‘NJ’;
c_pi CONSTANT NUMBER := 3.14;
v_invoicedate DATE DEFAULT SYSDATE;
In this example, you see a naming convention that uses prefix v_ for variables and
prefix c_ for constants.
ANCHORED DECLARATION
PL/SQL uses %TYPE attribute to anchor a variable’s data type. Another variable
or a column in a table can be used for anchoring. In anchoring, you tell PL/SQL to
ShahCh10v3.qxd 4/16/04 11:59 AM Page 235
use a variable or a column’s data type as the data type for another variable in the
program. The general syntax is
variablename typeattribute%TYPE [value assignment];
where typeattribute is another variable’s name or table’s column with a table qualifi-
er (e.g., tablename.columnname). It is very useful while retrieving a value of a col-
umn into a variable with a SELECT query in PL/SQL. For example,
DECLARE
v_num1 NUMBER(3);
v_num2 v_num1%TYPE;
in this example, v_num1 is declared with a data type NUMBER(3). The next vari-
able, v_num2, is declared using the anchoring method and the declaration attribute
%TYPE. The variable v_num2 gets the same data type as v_num1.
Two variables can also be declared and assigned data types to match the col-
umn’s data type. The advantage is that you do not have to cross-reference the data
type used in the table. Oracle does that for you. For example,
DECLARE
v_empsal employee.Salary%TYPE;
v_deptname dept.DeptName%TYPE;
Suppose you do not use the anchoring method to declare variables, which are
assigned values directly from table columns. You can use the DESCRIBE command
to list all the data types for columns. Then, you can declare variables in a program
with the same types and lengths. This will work just fine. The problem will arise when
the column lengths are increased to meet future demands. When you assign values
from those columns to variables, VALUE_ERROR will occur—and you will have
to go back to all the programs to change the variable’s data length! Anchoring defi-
nitely is an advantage in such situations.
A %TYPE declaration anchors the data type of one variable based on anoth-
er variable or column at the time of a PL/SQL block’s compilation. If the source or
original column’s data type is changed, the PL/SQL block must be recompiled to re-
anchor all anchored variables.
Nested Anchoring
If a source variable is declared with a NOT NULL constraint, the %TYPE declara-
tion inherits the NOT NULL constraint from the source, its anchor. The anchored
variable must be initialized with a value in the %TYPE declaration.
If the source for a %TYPE declaration is a table’s column, the NOT NULL
constraint is not inherited by the anchored variable. There is no need to initialize the
anchored variable, and it can be assigned a NULL value.
ASSIGNMENT OPERATION
The assignment operation is one of the ways to assign a value to a variable. You have
already learned that a variable can be initialized at the time of declaration by using
the DEFAULT option or :=. The assignment operation is used in the executable
section of the program block to assign a literal, another variable’s value, or the result
of an expression to a variable. The general syntax is
For example,
v_num1 := 100;
v_num2 := v_num1;
v_sum := v_num1 + v_num2;
In these examples, the assumption is made that three variables have already
been declared. The first example assigns 100 to the variable v_num1. The second ex-
ample assigns the value of the variable v_num1 to the variable v_num2. The third
example assigns the result of an addition operation on v_num1 and v_num2 to the
variable v_sum.
The following statements are examples of invalid assignment operations and
the reasons for their lack of validity:
BIND VARIABLES
Bind variables are also known as host variables. These variables are declared in the
host SQL * Plus environment and are accessed by a PL/SQL block. Anonymous
blocks do not take any arguments, but they can access host variables with a colon
prefix (:) and the host variable name. Host variables can be passed to procedures
and functions as arguments. A host variable is declared at the SQL 7 prompt with
the SQL * Plus VARIABLE statement. The syntax of a host variable declaration is
For example,
G_DOUBLE
-----------
10
SQL>
the local variable v_num, doubles it, and stores the result in the host variable
g_double. Finally, the resulting variable is printed in the host environment with a
PRINT statement.
The use of host variables should be minimized in a program block, because they
affect performance. Every time a host variable is accessed within the block, the PL/SQL
engine must stop to request the host environment for the value of the host variable.The
variable’s value can be assigned to a local variable to minimize calls to the host.
PL/SQL does not have any input capabilities in terms of having an input statement.
There are no explicit input/output (I/O) statements, but substitution variables of
SQL are available in PL/SQL. Substitution variables have limitations, which be-
come apparent in a loop.
Let us rewrite the program code in Figure 10-5 to the one in Figure 10-6. When
the code in Figure 10-6 is executed, a standard prompt for p_num appears on the
screen for users to type in a value for it. As you see in the example, there is no need
G_DOUBLE
-----------
20
SQL>
to declare substitution variables in the program block. The value of the bind/host
variable is printed with the PRINT command. The value of the local variable v_num
cannot be printed with the PRINT command, however, because the scope of a local
variable is within the block where it is declared.
When substitution variable is used in a program, the output contains lines
showing how the substitution was done. You can suppress those lines by using the
SET VERIFY OFF command before running the program.
PRINTING IN PL/SQL
There is no explicit output statement in PL/SQL. Oracle does have a built-in package
called DBMS_OUTPUT with the procedure PUT_LINE to print. An environment
variable named SERVEROUTPUT must be toggled ON to view output from it.
The DBMS_OUTPUT is the most frequently used package because of its ca-
pabilities to get lines from a file and to put lines into the buffer. The PUT_LINE
procedure displays information passed to the buffer and puts a new-line marker at
the end. For example,
DBMS_OUTPUT.PUT_LINE (‘This line will be displayed’);
SQL>
displaying information from the buffer, but it does not put a new-line marker at the
end. If there is another DBMS_OUTPUT.PUT or DBMS_OUTPUT.PUT_LINE
statement following that statement, its output will be displayed on the same line.
ARITHMETIC OPERATORS
Five standard arithmetic operators are available in PL/SQL for calculations. If more
than one operator exists in an arithmetic expression, the following order of prece-
dence is used:
Addition
Subtraction and negation
* Multiplication
/ Division
** Exponentiation
–2 + 3 * (10 – 2 * 3)/6
Answer: 0 (The operations within the parentheses are performed first, with
multiplication followed by subtraction. The result from within the paren-
theses is multiplied by 3, and that result is divided by 6. Finally, the result is
added to -2)
In this chapter, you learned the basics of PL/SQL. In the next chapter, you will
learn about three programming control structures: sequence, selection, and looping.
(You already know one of them. All examples in this chapter were based on sequence
ShahCh10v3.qxd 4/16/04 11:59 AM Page 241
In a Nutshell . . . 241
structure.) You will also learn to interface with the Oracle server by embedding
SQL statements in PL/SQL program blocks.
IN A NUTSHELL . . .
11
More on PL/SQL:
Control Structures
and Embedded SQL
IN THIS CHAPTER . . .
In the previous chapter, you learned the basics of the PL/SQL programming language.
You are now able to write simple programs using local, host, and substitution variables;
can perform simple calculations by using assignment statements; and know how to use
Oracle’s built-in package DBMS_OUTPUT.PUT_LINE in program blocks to display
results from the buffer. The sample programs and lab exercises have a series of state-
ments that are executed from the beginning to the end in a linear fashion. When an
anonymous block is executed, the code is sent to the PL/SQL engine for compilation.
In this chapter, you will see the use of different control structures employed in a high-
level programming language.
In the last chapter, you saw how to write PL/SQL programs independent of a
database. We start with more independent PL/SQL programs, and then show the actual
use of PL/SQL to interact with the Oracle database. A PL/SQL program block “talks”
to the Oracle database by embedding SQL statements in its executable section.
ShahCh11v3.qxd 4/16/04 12:00 PM Page 245
CONTROL STRUCTURES
In a procedural language like PL/SQL, there are three basic programming control
structures:
Selection Structure
Equal to
<>or ! Not equal to
> Greater than
> Greater than or equal to
< Less than
< Less than or equal to
AND OR NOT
TRUE AND TRUE = TRUE TRUE OR TRUE = TRUE NOT TRUE = FALSE
TRUE AND FALSE = FALSE TRUE OR FALSE = TRUE NOT FALSE = TRUE
FALSE AND TRUE = FALSE FALSE OR TRUE = TRUE NOT NULL = NULL
FALSE AND FALSE = FALSE FALSE OR FALSE = FALSE
NULL AND TRUE = NULL NULL OR TRUE = TRUE
NULL AND FALSE = FALSE NULL OR FALSE = NULL
NULL AND NULL = NULL NULL OR NULL = NULL
Figure 11-3 Truth tables for AND, OR, and NOT operators.
Other special operators (IS NULL, IN, LIKE, and BETWEEN Á AND) dis-
cussed in the SQL section are also available in PL/SQL. PL/SQL has five condition-
al or selection statements available for decision making:
IF condition(s) THEN
Action statements
END IF;
For example, Figure 11-4 shows a simple IF statement with an output statement,
which will be performed if the day entered is ‘SUNDAY’. If the condition is false,
the statement is skipped. In this example, notice the use of the relational operator
equals 1=2 in a Boolean condition and of the assignment operator 1:= 2 in the action
assignment statement.
ShahCh11v3.qxd 4/16/04 12:00 PM Page 247
SQL> DECLARE
2 V_DAY VARCHAR2(9) := ’&DAY’;
3 BEGIN
4 IF (V_DAY = ’SUNDAY’) THEN
5 DBMS_OUTPUT.PUT_LINE(’SUNDAY IS A HOLIDAY!’);
6 END IF;
7 END;
8 /
Enter value for day: SUNDAY
SUNDAY IS A HOLIDAY
SQL> /
Enter value for day: MONDAY
SQL>
You must have noticed the indentation in the program code. All program
statements can start in the first column. In fact, you can write more than one state-
ment on one line with the appropriate punctuation mark (;) separating them. Such
programming practice, however, can make your program difficult to read. In turn, it
is a good practice to indent statements within a block or a compound statement, be-
cause it makes your program more readable. A program will work just the same
without indenting statements or without adding a comment to it, but good program-
ming practices make everybody’s life easier.
IF condition(s) THEN
Action statements 1
ELSE
Action statements 2
END IF;
If the condition’s outcome is TRUE, action statements 1 are performed. If the out-
come is FALSE, action statements 2 are performed. One set of statements is skipped
in any case.
For an example, see Figure 11-5. If the entered age is 18 or older, age is dis-
played with string ADULT; otherwise, age is displayed with string MINOR.
ShahCh11v3.qxd 4/16/04 12:00 PM Page 248
SQL> /
Enter value for age: 12
AGE: 12 - MINOR
PL/SQL procedure successfully completed.
SQL>
Notice the word ELSIF, which does not have the last E in ELSE. ELSIF is a
single word, but END IF uses two words. For example, let us revisit the DECODE
function example of Chapter 6 (see Figure 11-6). Figure 11-7 shows the ELSIF
equivalent of the DECODE function.
The same statement can be written with a simple IF statement, though less effi-
ciently. You will need five simple IF statements to accomplish the same task as that
performed by a single compound ELSIF statement. Let us take another example
ShahCh11v3.qxd 4/16/04 12:00 PM Page 249
SQL> DECLARE
2 v_pos NUMBER(1) := &Position;
3 BEGIN
4 IF v_pos=1 THEN
5 DBMS_OUTPUT.PUT_LINE(’20% increase’);
6 ELSIF v_pos=2 THEN
7 DBMS_OUTPUT.PUT_LINE(’15% increase’);
8 ELSIF v_pos=3 THEN
9 DBMS_OUTPUT.PUT_LINE(’10% increase’);
10 ELSIF v_pos=4 THEN
11 DBMS_OUTPUT.PUT_LINE(’5% increase’);
12 ELSE
13 DBMS_OUTPUT.PUT_LINE(’No increase’);
14 END IF;
15 END;
16 /
Enter value for position: 2
15% increase
PL/SQL procedure successfully completed.
SQL>
with compound conditions. First, we will use a simple IF statement (see Fig. 11-8),
and then, we will rewrite it by using ELSIF (Figure 11-9).
The example here assigns a grade of A, B, C, D, or F based on v_score. We are
assuming that the score is within the range of 0 to 100. You will need five simple IF
statements with total of 10 conditions or two conditions per each statement. Now,
suppose the value of v_score is 95. The first statement’s condition is TRUE, so
v_grade will be assigned ‘A’. Because all simple IF statements are independent state-
ments, the execution will continue with the next IF, and so on. There is no other
TRUE condition for v_score equal to 95, so v_grade will be ‘A’ after execution of all
five IF statements. This slows down your program’s execution. The ELSIF, on the
other hand, is one compound statement, and it stops as soon as a match is found. Let
us see how the ELSIF statement looks.
SQL> DECLARE
2 S NUMBER(3) := &SCORE;
3 GRADE CHAR;
4 BEGIN
5 IF S >= 90 AND S <= 100 THEN
6 GRADE := ’A’;
7 END IF;
8 IF S >= 80 AND S <= 89 THEN
9 GRADE := ’A’;
10 END IF;
11 IF S >= 70 AND S <= 79 THEN
12 GRADE := ’C’;
13 END IF;
14 IF S >= 60 AND S <= 69 THEN
15 GRADE := ’D’;
16 END IF;
17 IF S >= 0 AND S <= 59 THEN
18 GRADE := ’F’;
19 END IF;
20 IF S < 0 AND S > 100 THEN
21 GRADE := ’U’;
22 END IF;
23 DBMS_OUTPUT.PUT_LINE(’SCORE IS ’ || TO_CHAR(S));
24 DBMS_OUTPUT.PUT_LINE(’GRADE IS ’ || GRADE);
25 END;
26 /
Enter value for score: 93
SCORE IS 93
GRADE IS A
PL/SQL procedure successfully completed.
SQL>
SQL> DECLARE
2 S NUMBER(3) := &SCORE;
3 GRADE CHAR;
4 BEGIN
5 IF S >= 90 AND S <= 100 THEN
6 GRADE := ’A’;
7 ELSIF S >= 80 AND S <= 89 THEN
8 GRADE := ’B’;
9 ELSIF S >= 70 THEN
10 GRADE := ’C’;
11 ELSIF S >= 60 THEN
12 GRADE := ’D’;
13 ELSIF S >= 0 THEN
14 GRADE := ’F’;
15 ELSIF S < 0 AND S > 100 THEN
16 GRADE := ’U’;
17 END IF;
18 DBMS_OUTPUT.PUT_LINE(’SCORE IS ’ || TO_CHAR(S));
19 DBMS_OUTPUT.PUT_LINE(’GRADE IS ’ || GRADE);
20 END;
21 /
Enter value for score: 77
SCORE IS 77
GRADE IS C
PL/SQL procedure successfully completed.
SQL>
The ELSIF statement reduces the number of conditions from 10 to 5 and the
number of statements from five to one. Now, let us consider the same value, 95, as be-
fore.The condition is TRUE in the first IF clause, and v_grade is assigned value ‘A’.The
statement will not continue down anymore, because it will not enter the ELSIF part.
The rest of the statement is ignored, thus making ELSIF more efficient than its coun-
terpart (see Fig. 11-9). In this example, there is an added ELSIF statement to check for
invalid scores (below 0 as well as above 100), which result in an undefined (‘U’) grade.
1. Male 25 or over.
2. Male under 25.
3. Female 25 or over.
4. Female under 25.
SQL> DECLARE
2 V_GENDER CHAR := ’&SEX’;
3 V_AGE NUMBER(2) := ’&AGE’;
4 V_CHARGE NUMBER(3,2);
5 BEGIN
6 IF (V_GENDER = ’M’ AND V_AGE >= 25) THEN
7 V_CHARGE := 0.05;
8 END IF;
9 IF (V_GENDER = ’M’ AND V_AGE < 25) THEN
10 V_CHARGE := 0.10;
11 END IF;
12 IF (V_GENDER = ’F’ AND V_AGE >= 25) THEN
13 V_CHARGE := 0.03;
14 END IF;
15 IF (V_GENDER = ’F’ AND V_AGE < 25) THEN
16 V_CHARGE := 0.06;
17 END IF;
18 DBMS_OUTPUT.PUT_LINE(’GENDER: ’ || V_GENDER);
19 DBMS_OUTPUT.PUT_LINE(’AGE: ’ || TO_CHAR(V_AGE));
20 DBMS_OUTPUT.PUT_LINE(’SURCHARGE: ’ || TO_CHAR(V_CHARGE));
21 END;
22 /
Enter value for sex: F
Enter value for age: 18
GENDER: F
AGE: 18
SURCHARGE: .06
SQL>
Now, we will rewrite the code done with a simple IF in Figure 11-12 by using
nested IF statements (see Fig. 11-13). Again, remember that the nested IF statement
will make the code more efficient than the simple IF version. The THEN portion of
the outer IF calculates the insurance surcharge for male individuals, and the ELSE
portion calculates the same for the female individuals. The inner IF statements in
each portion check for the age.
Looping Structure
SQL> DECLARE
2 V_GENDER CHAR := ’&SEX’;
3 V_AGE NUMBER (2) := ’&AGE’;
4 V_CHARGE NUMBER (3,2);
5 BEGIN
6 IF (V_GENDER = ’M’) THEN /* MALE */
7 IF (V_AGE >= 25) THEN
8 V_CHARGE := 0.05;
9 ELSE
10 V_CHARGE := 0.10;
11 END IF;
12 ELSE /* FEMALE */
13 IF (V_AGE >= 25) THEN
14 V_CHARGE := 0.03;
15 ELSE
16 V_CHARGE := 0.06;
17 END IF;
18 END IF;
19 DBMS_OUTPUT.PUT_LINE(’GENDER: ’ || V_GENDER);
20 DBMS_OUTPUT.PUT_LINE(’AGE: ’ || TO_CHAR(V_AGE));
21 DBMS_OUTPUT.PUT_LINE(’SURCHARGE: ’||TO_CHAR(V_CHARGE));
22 END;
23 /
Enter value for sex: F
Enter value for age: 18
GENDER: F
AGE: 18
SURCHARGE: .06
SQL>
1. Basic loop.
2. WHILE loop.
3. FOR loop.
Each loop has different syntax, and each works somewhat differently.
LOOP
Looping statement1;
Looping statement2;
...
Looping statementN;
EXIT [WHEN condition];
END LOOP;
You can also add a condition with the optional WHEN clause that will end the
loop when the condition becomes true. For example,
The condition is not checked at the top of the loop, but it is checked inside the
body of the loop. The basic loop is performed at least once, because the condition is
tested after entering the body of the loop. Such a loop is also called a post-test loop.
The example shown in Figure 11-14 uses a counter to control the number of
loop executions. There are three necessary statements in a counter-controlled loop.
The counter must be initialized, the value of the counter must change within the
loop (increment or decrement), and a proper condition must exist in the loop. If
value of the counter is not changed inside the loop, it will result in an infinite loop.
The initial value, the increment/decrement, and the condition control the total num-
ber of loop executions.
ShahCh11v3.qxd 4/16/04 12:00 PM Page 256
SQL>
Answer: One time (the loop is performed once and the first check of condi-
tion returns true, so the loop ends). Tricky, isn’t it?
Answer: The loop is infinite (the condition will never become true).
ShahCh11v3.qxd 4/16/04 12:00 PM Page 257
WHILE loop. The WHILE loop is an alternative to the basic loop and is per-
formed as long as the condition is true. It terminates when the condition becomes false.
If the condition is false at the beginning of the loop, the loop is not performed at all.The
WHILE loop does not need an EXIT statement to terminate. The general syntax is
WHILE condition LOOP
Looping statement1;
Looping statement2;
...
Looping statement n;
END LOOP;
In Figure 11-15, you see the same average program of Figure 11-14 rewritten
with the WHILE loop. There are obvious differences between the basic loop and the
WHILE loop. Figure 11-16 explains the differences between them.
It is performed as long as the condition is false. It is performed as long as the condition is true.
It tests the condition inside the loop It checks condition before entering the loop
(post-test loop). (pretest loop).
It is performed at least one time. It is performed zero or more times.
It needs the EXIT statement to terminate. There is no need for an EXIT statement.
FOR loop. The FOR loop is the simplest loop you can write. Unlike the basic
and WHILE loops, you do not have to initialize, test, and increment/decrement the
loop control variable separately.You do it in the loop’s header.There is no need to use
an EXIT statement, and the counter need not be declared. The counter used in the
loop is implicitly declared as an integer, and it is destroyed on the loop’s termination.
The counter may not be used within the loop body in an assignment statement as a
target variable. The general syntax is
Looping statementN
END LOOP;
The counter varies from the lower value to the upper value, incrementing by
one with every loop execution. The loop can also be used with the counter starting
at a higher value and decrementing by one with every loop execution. The key word
REVERSE is used for varying the counter in the reverse order, or from a higher to
a lower value.
The program in Figure 11-17 does not declare v_count, and there is no condi-
tion or explicit statement to change the counter’s value. The same program with the
counter’s value in reverse order will only change by one line. The FOR statement
will look like
SQL> DECLARE
2 V_COUNT NUMBER(2);
3 V_SUM NUMBER(2) := 0;
4 V_AVG NUMBER(3,1);
5 BEGIN
6 FOR V_COUNT IN 1..10 LOOP
7 V_SUM := V_SUM + V_COUNT;
8 END LOOP;
9 V_AVG := V_SUM / 10;
10 DBMS_OUTPUT.PUT_LINE
11 (’AVERAGE OF 1 TO 10 IS ’ || TO_CHAR(V_AVG));
12 END;
13 /
AVERAGE OF 1 TO 10 IS 5.5
SQL>
One important point about the loop-control variable is that it is declared, in-
cremented/decremented, and destroyed implicitly, but its value cannot be changed
explicitly within the FOR loop’s body. It cannot be a target variable in an assign-
ment statement.
Nested loops. You can use a loop within another loop. Loops can be nest-
ed to many levels. When the inner loop ends, it does not automatically end the outer
loop enclosing it. You can end an outer loop from within the inner loop by labeling
each loop and then using the EXIT statement. EXIT WHEN exits the current loop,
but EXIT out_loop WHEN also exits the outer loop. The loop labels use the same
naming rules as those used for identifiers. The loops are labeled before the key word
LOOP on the same line or on a separate line. The loop label is enclosed within two
pairs of angle brackets (V and W ). For example,
<<out_loop>>
LOOP
...
EXIT WHEN condition;
<<in_loop>>
LOOP
...
EXIT out_loop WHEN condition; /* exits out_loop */
EXIT WHEN condition; /*exits in_loops */
...
END LOOP in_loop; /* label optional here */
...
END LOOP out_loop; /*label optional here */
NESTED BLOCKS
PL/SQL block may contain another PL/SQL block; in other words, PL/SQL blocks
can be nested. The execution starts with the outer block and continues with the
inner block. The variables declared in the outer block are global to the inner block,
and they are accessible in the inner block. The variables declared in the inner block,
however, are not accessible in the outer block. For example,
DECLARE /* Outer block starts here.*/
Var1 NUMBER; /* known to outer and inner*/
BEGIN
... /* can use Var1 here */
DECLARE /*Inner block starts here.*/
Var2 NUMBER; /* known to inner block */
BEGIN
... /* can use Var1 and Var2 here */
END; /* Inner block ends here.*/
... /* can use Var1 here */
END; /* Outer block ends here.*/
ShahCh11v3.qxd 4/16/04 12:00 PM Page 260
SQL IN PL/SQL
The PL/SQL statements have control structures for calculations, decision making,
and iterations. You need to use SQL to interface with the Oracle database. When
changes are necessary in the database, SQL can be used to retrieve and change in-
formation. PL/SQL supports all Data Manipulation Language (DML) statements,
such as INSERT, UPDATE, and DELETE. It also supports the Transaction Control
Language statements ROLLBACK, COMMIT, and SAVEPOINT. You can retrieve
data using the data retrieval statement SELECT. A row of data can be used to as-
sign values to variables. More than one row can be retrieved and processed using
cursors (covered in the next chapter). PL/SQL statements can use single-row func-
tions, but group functions are not available for PL/SQL statements. SQL statements
in the PL/SQL block, however, can still utilize those group functions.
PL/SQL does not support Data Definition Language (DDL) statements, such
as CREATE, ALTER, and DROP. The Data Control Language (DCL) statements
GRANT and REVOKE also are not available in PL/SQL.
The SELECT statement retrieves data from Oracle tables. The syntax of SELECT is
different in PL/SQL, however, because it is used to retrieve values from a row into a
list of variables or into a PL/SQL record. The general syntax is
SELECT columnnames
INTO variablenames / RecordName
FROM tablename
WHERE condition;
where columnnames must contain at least one column and may include arithmetic
or string expressions, single-row functions, and group functions. Variablenames must
contain a list of local or host variables to hold values retrieved by the SELECT
clause. The variables are declared either at the SQL * Plus prompt or locally under
the DECLARE section (see Fig. 11-18). The recordname is a PL/SQL record (cov-
ered in the next chapter). All the features of SELECT in SQL are available with an
added mandatory INTO clause.
The INTO clause must contain one variable for each value retrieved from the
table. The order and data type of the columns and variables must correspond. The
SELECT Á INTO statement must return one and only one row. It is your respon-
sibility to code a statement that returns one row of data. If no rows are returned, the
standard exception (error condition) NO_DATA_FOUND occurs. If more than one
row are retrieved, the TOO_MANY_ROWS exception occurs. You will learn more
about exceptions and exception handling in the next chapter.
In Figure 11-18, a few columns from a row of the EMPLOYEE table are re-
trieved into a series of variables. The variables can be declared with data types, but
more appropriately, attribute %TYPE is used to avoid any data-type mismatches.
The SQL statement in PL/SQL ends with a semicolon (;). The INTO clause is
mandatory in a SELECT statement when used in a PL/SQL block. Figure 11-19
ShahCh11v3.qxd 4/16/04 12:00 PM Page 261
SQL> DECLARE
2 V_LAST EMPLOYEE.LNAME%TYPE;
3 V_FIRST EMPLOYEE.FNAME%TYPE;
4 V_SAL EMPLOYEE.SALARY%TYPE;
5 BEGIN
6 SELECT LNAME, FNAME, SALARY
7 INTO V_LAST, V_FIRST, V_SAL
8 FROM EMPLOYEE
9 WHERE EMPLOYEEID = 200;
10 DBMS_OUTPUT.PUT_LINE
11 (’EMPLOYEE NAME: ’ || V_FIRST || ’ ’ || V_LAST );
12 DBMS_OUTPUT.PUT_LINE
13 (’SALARY: ’ || TO_CHAR(V_SAL));
14 END;
15 /
EMPLOYEE NAME: Jinku Shaw
SALARY: 24500
SQL>
SQL> DECLARE
2 V_ID EMPLOYEE.EMPLOYEEID%TYPE;
3 V_DEPT EMPLOYEE.DEPTID%TYPE := &DEPT_NUM;
4 BEGIN
5 SELECT EMPLOYEEID INTO V_ID
6 FROM EMPLOYEE WHERE DEPTID = V_DEPT;
7 END;
8 /
Enter value for dept_num: 10
DECLARE
*
ERROR at line 1:
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at line 5
SQL> /
Enter value for dept_num: 50
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 5
SQL>
shows another example that results in exceptions because the SELECT Á INTO
statement returns either too many rows or no data.
You can use all DML statements in PL/SQL with the same syntax you used in SQL.
The three DML statements to manipulate data are:
INSERT Statement
SQL> BEGIN
2 INSERT INTO EMPLOYEE
3 (EMPLOYEEID, LNAME, FNAME, SALARY, DEPTID)
4 VALUES
5 (EMPLOYEE_EMPLOYEEID_SEQ.NEXTVAL, ’RAI’,
6 ’AISH’, 90000, DEPT_DEPTID_SEQ.CURRVAL);
7 COMMIT;
8 END;
9 /
SQL>
DELETE Statement
We will show the use of the DELETE statement in the PL/SQL block to remove
some rows. Suppose the NamanNavan (N2) Corporation decides to remove the IT
Department. All the employees belonging to that department must be removed
ShahCh11v3.qxd 4/16/04 12:00 PM Page 263
SQL> DECLARE
2 V_DEPTID DEPT.DEPTID%TYPE;
3 BEGIN
4 SELECT DEPTID
5 INTO V_DEPTID
6 FROM DEPT
7 WHERE UPPER(DEPTNAME) = ’&DEPT_NAME’
8 DELETE FROM EMPLOYEE
9 WHERE DEPTID = V_DEPTID;
10 COMMIT;
11 END;
12 /
Enter value for dept_name: IT
SQL>
from the EMPLOYEE table. Figure 11-21 shows the DELETE statement in
PL/SQL.
UPDATE Statement
The UPDATE statement can be used in a PL/SQL block for modification of data.
The company decides to give a bonus commission to all the employees who are en-
titled to commission. The bonus is 10% of the commission received. Figure 11-22
shows an example of an UPDATE statement in PL/SQL block to modify commission.
SQL> DECLARE
2 V_INCREASE NUMBER := &DECIMAL_INCREASE;
3 BEGIN
4 UPDATE EMPLOYEE
5 SET SALARY = SALARY * (1 + V_INCREASE)
6 WHERE EMPLOYEEID = &EMP_ID;
7 COMMIT;
8 END;
9 /
Enter value for decimal_increase: 0.15
Enter value for emp_id: 545
SQL>
You know what a transaction is. You also know the transaction control capabilities
in Oracle. (If you don’t remember, review Chapter 9). In Figures 11-18, 11-19, and
11-20, after performing a DML statement, the sample blocks have used a COMMIT
statement. You do not have to commit within a PL/SQL block. If you do decide to
use it, your data will be written to the disk right away, and the locks from those rows
will be released. All transaction control statements are allowed in PL/SQL, and they
are as follows:
IN A NUTSHELL . . .
● The three control structures in PL/SQL are sequence, selection, and looping.
● In a sequence structure, the instructions are performed in a linear order.
● The selection structure involves decision making based on the outcome of a
Boolean expression.
● The looping structure contains a series of instructions that are performed
repeatedly.
● Four selection structure statements in PL/SQL are IF . . . THEN . . . END IF,
IF . . . THEN . . . ELSE . . . END IF, IF . . . THEN . . . ELSIF . . . END IF,
and CASE statements.
● A CASE statement uses a variable as a selector and checks its value in
WHEN clauses.
● A searched CASE statement does not use a variable as a selector, but it
does use conditions in WHEN clauses.
● Boolean expressions or conditions use relational operators 1= , 6 7 or ! = ,
7, 7 = , 6, and 6 = 2, logical operators (AND, OR, and NOT), and other op-
erators (BETWEEN. . .AND, IS NULL, and LIKE).
● It is good practice to add comments to a program and indent statements
within a programming block.
● The three types of loops in PL/SQL are the basic loop, WHILE loop, and
FOR loop.
● The basic loop is performed at least once and for as long as the condition is
false. It is known as a post-test loop. The basic loop needs the EXIT state-
ment to terminate.
ShahCh12v3.qxd 4/16/04 12:01 PM Page 267
12
PL/SQL Cursors
and Exceptions
IN THIS CHAPTER . . .
● You will learn about a private work area for an SQL statement and its active
set, called a cursor.
● You will be introduced to implicit and explicit cursor types.
● You will perform open, fetch, and close actions on explicit cursors.
● Use of cursor FOR loops and its implied statements are explained.
● Cursors with parameters and variable cursors are introduced.
● PL/SQL errors, known as exceptions, and their types are discussed.
● The process of declaring, raising, and handling different types of exceptions
is covered.
In previous chapters, you learned about different control structures: sequence, se-
lection, and looping. All structured programming languages support these struc-
tures. Other statements are also available in most of the languages. One of these
additional statements is the GOTO statement, which allows you to branch uncondi-
tionally. All you have to code is GOTO V labelname W, and the control shifts to the
statement after the label. The GOTO statement, though available, is not preferred,
however, because of its nonstructured nature. You also know how to use an SQL
statement within a PL/SQL block for data retrieval, data manipulation, and transac-
tion control.
ShahCh12v3.qxd 4/16/04 12:01 PM Page 268
In this chapter, you will learn about some advanced features of PL/SQL, such
as retrieving more than one row from a database into a work area called a cursor.
One of the strongest benefits of PL/SQL is its error-handling capabilities. The error
conditions, known as exceptions, in PL/SQL, are also covered in this chapter.
CURSORS
When you execute an SQL statement from a PL/SQL block, Oracle assigns a private
work area for that statement. The work area, called a cursor, stores the statement
and the results returned by execution of that statement. A cursor is created either
implicitly or explicitly by you.
Types of Cursors
1. In a static cursor, the contents are known at compile time. The cursor ob-
ject for such an SQL statement is always based on one SQL statement.
2. In a dynamic cursor, a cursor variable that can change its value is used.
The variable can refer to different SQL statements at different times.
This chapter covers static cursors in detail. It also introduces you to the new
concept of dynamic cursors using a cursor variable. The static cursors are of two
types as well:
IMPLICIT CURSORS
PL/SQL creates an implicit cursor when an SQL statement is executed from within
the program block. The implicit cursor is created only if an explicit cursor is not at-
tached to that SQL statement. Oracle opens an implicit cursor, and the pointer is set
to the first (and the only) row in the cursor. Then, the SQL statement is fetched and
executed by the SQL engine on the Oracle server. The PL/SQL engine closes the
ShahCh12v3.qxd 4/16/04 12:01 PM Page 269
CURSOR deptname_cur IS
SELECT DeptName, Location FROM dept WHERE DeptId = 10;
Here, only one row is retrieved by the cursor with two column values, Finance and
Charlotte, which later can be assigned to variables by fetching that row.
EXPLICIT CURSORS
1. Declare it.
2. Open it.
3. Fetch row(s) from it.
4. Close it.
DECLARE
CURSOR cursorname IS
SELECT statement;
ShahCh12v3.qxd 4/16/04 12:01 PM Page 270
where cursorname is the name of the cursor that follows identifier-naming rules. The
SELECT statement is any valid data-retrieval statement. The cursor declaration is
done in the DECLARE section of the PL/SQL block, but a cursor cannot be used in
programming statements or expressions, as with other variables.
For example, Figures 12-1 and 12-2 show declarations of two cursors. In Figure
12-1, the cursor is based on a SELECT query that will retrieve all rows from the
DEPT table in the work area. In the Figure 12-2, two columns, EmployeeId and
Salary, are selected into the cursor with DeptId equal to 20.
SQL> DECLARE
2 CURSOR DEPT_CUR
3 IS
4 SELECT *
5 FROM DEPT;
6 BEGIN
7 ...
8 END;
SQL> DECLARE
2 CURSOR EMPLOYEE_CUR
3 IS
4 SELECT EMPLOYEEID, SALARY
5 FROM EMPLOYEE
6 WHERE DEPTID = 20;
7 BEGIN
8 ...
9 END;
Actions are performed on cursors declared in the DECLARE section of the block.
Before rows can be retrieved from a cursor, you must open the cursor.
ShahCh12v3.qxd 4/16/04 12:01 PM Page 271
For example,
OPEN employee_cur;
You must open a cursor that has not been opened in the program block or is
closed to retrieve data into it. If you try to open a cursor that is already open, the fol-
lowing Oracle error message appears:
PLS-06511:PL/SQL: cursor already open
Notice the change in the error message prefix PLS! The errors with prefix ORA are
Oracle database errors, and the errors with prefix PLS are PL/SQL errors.You will
see later how this can be avoided using the cursor attribute %ISOPEN.
where variablelist may include a local variable, a table, or a bind variable and
recordname is the name of a record structure. For example,
FETCH employee_cur INTO v_empnum, v_sal;
or
FETCH employee_cur INTO emp_rec;
In the first example, two columns, EmployeeID and Salary, are retrieved into
v_empnum and v_sal, respectively. The number of items matches the number of
variables in the SELECT statement. The order of items and variables must also
match. The variables should be declared with a %TYPE declaration variable to en-
sure the correct data type. If the number of items in SELECT does not match the
number of variables, it results in the following compiler error:
PLS-00394:wrong number of values in the INTO list of a FETCH statement
ShahCh12v3.qxd 4/16/04 12:01 PM Page 272
The second example of FETCH uses a record. A composite data type can be
used for the record instead of the CursorName%ROWTYPE declaration. You will
learn about the record data type in the next chapter.
Suppose you opened a cursor in a PL/SQL block to retrieve data from a table,
and then inserts, deletes, and updates are performed on that table after the OPEN
statement is executed. Oracle enforces read consistency, and the data manipulation
statements are ignored. You will have the same data from the point of execution of
OPEN to the point of execution of CLOSE statements. Changing data in the under-
lying table does not change data in the work area.
Closing a cursor. When you are done with a cursor, you should close it. A
closed cursor can be reopened again. If you terminate your PL/SQL program with-
out closing an open cursor, it will not result in an exception. In fact, the local cursor
declared in a PL/SQL block is closed automatically when the block terminates. It is
a good habit, however, to close an open cursor before terminating the block. There
is a limit to the number of cursors a user may open simultaneously. The default value
is in a parameter called OPEN_CURSORS, which has default value of 50. A user re-
leases memory by closing a cursor. PL/SQL uses the CLOSE statement to close a
cursor. The general syntax is
CLOSE cursorname;
For example,
CLOSE employee_cur;
Actions can be performed on cursors with OPEN, FETCH, and CLOSE statements.
You can get information about the current status of a cursor or the result of the last
fetch by using cursor attributes. The four explicit cursor attributes are:
%ISOPEN
The %ISOPEN attribute is useful in making sure that you do not open a cursor that
is already open. It is also appropriate for making sure that a cursor is open before
ShahCh12v3.qxd 4/16/04 12:01 PM Page 273
trying to fetch from it. For example, Figure 12-3 tests to see if a cursor is open. If it is
not open, already, the cursor is opened. Then, execution continues with a loop and a
fetch in it.
SQL>
%FOUND
The %FOUND attribute returns a TRUE if the last FETCH returned a row; other-
wise, it returns a FALSE. For example, Figure 12-3 shows a block segment that exits
the loop if a row is not found. The loop continues as long as a row is fetched.
%NOTFOUND
The %NOTFOUND attribute returns a TRUE if the last FETCH did not return a
row; otherwise, it returns a FALSE. It is the opposite of the %FOUND attribute.
ShahCh12v3.qxd 4/16/04 12:01 PM Page 274
The statement
EXIT WHEN NOT employee_cur%FOUND;
can be written as
EXIT WHEN employee_cur%NOTFOUND;
%ROWCOUNT
When a cursor is opened and no fetch is done from it, %ROWCOUNT is equal to
zero. With every fetch, %ROWCOUNT is incremented by one. The cursor must be
open before using %ROWCOUNT on it. For example, the code in Figure 12-3 goes
through the loop as long as a row is fetched. A count of the number of rows fetched
is kept by the PL/SQL engine. In the code, we are printing the total number of rows
fetched by the cursor at the end.
An implicit cursor cannot be opened, fetched from, or closed with a statement. You
do not name implicit cursors. The cursor attributes are available for an implicit cur-
sor with the name SQL as a prefix. The four attributes for a implicit cursor are:
1. SQL%ISOPEN.
2. SQL%ROWCOUNT.
3. SQL%NOTFOUND.
4. SQL%FOUND.
The cursor FOR loop is the easiest way to write a loop for explicit cursors. The cur-
sor is opened implicitly when the loop starts. A row is then fetched into the record
from the cursor with every iteration of the loop. The cursor is closed automatically
when the loop ends, and the loop ends when there are no more rows. The cursor
ShahCh12v3.qxd 4/16/04 12:01 PM Page 275
FOR loop automates all the cursor actions. The general syntax is
where recordname is the name of the record that is declared implicitly in the loop
and is destroyed when the loop ends and cursorname is the name of declared ex-
plicit cursor.
Figure 12-4 uses a Cursor FOR loop with a record. When the loop starts, the
cursor is opened implicitly. During the loop execution, an implicit fetch retrieves a
row into the record for processing with each loop iteration. When an implicit fetch
cannot retrieve a row, the cursor is closed, and the loop terminates. The OPEN,
FETCH, and CLOSE statements are missing, because these operations are per-
formed implicitly. The record’s columns are addressed with recordname.columnname
notation. If the record is accessed after the END LOOP statement, it will throw an
exception, because the record’s scope is only within the loop body.
SQL>
Use of a subquery in the cursor FOR loop eliminates declaration of an explicit cursor.
The cursor is created by a subquery in the FOR loop statement itself. In Figure 12-5,
an explicit cursor is used with implicit actions. One thing that is missing is the cursor
name. The cursor declaration is not necessary, because it is created through the sub-
query. This subquery is similar to the inline view covered in the SQL section of this
text.
SQL> BEGIN
2 FOR EMP_REC IN
3 (SELECT FNAME, LNAME, SALARY, COMMISSION
4 FROM EMPLOYEE
5 WHERE DEPTID = 10) LOOP
6 DBMS_OUTPUT.PUT_LINE
7 (EMP_REC.FNAME || ’ ’ || EMP_REC.LNAME || ’ $’ ||
8 TO_CHAR(EMP_REC.SALARY + NVL(EMP_REC.COMMISSION, 0)));
9 END LOOP;
10 END;
11 /
John Smith $300000
Sandi Roberts $75000
Sunny Chen $35000
SQL>
When you type a SELECT query, the result is returned to you without locking any
rows in the table. Row locking is kept to a minimum. You can explicitly lock rows for
update before changing them in the program. The FOR UPDATE clause is used
with the SELECT query for row locking. The locked rows are not available to other
users for DML statements until you release them with COMMIT or ROLLBACK
commands. Rows that are locked for update do not have to be updated. The general
syntax is
CURSOR cursorname IS
SELECT columnnames
FROM tablename(s)
[WHERE condition]
FOR UPDATE [OF columnnames] [NOWAIT];
ShahCh12v3.qxd 4/16/04 12:01 PM Page 277
UPDATE tablename
SET clause
WHERE CURRENT OF cursorname;
_______________________________
DELETE FROM tablename
WHERE CURRENT OF cursorname;
You do not have to use a separate WHERE condition. The WHERE CURRENT
OF clause references the cursor, and changes apply to only the last fetched row.
A cursor can be declared with parameters, which allow you to pass values to the cur-
sor. These values are passed to the cursor when it is opened, and they are used in the
query when it is executed. With the use of parameters, you can open and close a cur-
sor many times with different values. The cursor with different values will then re-
turn different active sets each time it is opened. When parameters are passed, you
need not worry about the scope of variables. The general syntax is
CURSOR cursorname
[(parameter1 datatype, parameter2 datatype, . . .)]
IS
SELECT query;
where parameter1, parameter2, and so on are formal parameters passed to the cursor
and datatype is any scalar data type assigned to the parameter. The parameters are
assigned only data types; they are not assigned size.
When a cursor is opened, values are passed to the cursor. Each value must
match the positional order of the parameters in a cursor’s declaration. The values
ShahCh12v3.qxd 4/16/04 12:01 PM Page 278
can be passed through literals, PL/SQL variables, or bind variables. The parameters
in a cursor are passed in to the cursor, but you cannot pass any value out of the cur-
sor through parameters.
For example, in the PL/SQL program of Figure 12-6, the cursor employee_cur
is declared with a parameter dept_num, which is also used in the cursor SELECT
statement’s WHERE clause. When the program executes, it asks to input a value for
department number with substitution variable DEPARTMENT_ID, which is as-
signed to variable D_ID. The cursor is opened with parameter D_ID, which has
value of 10 as entered by the user. The format parameter DEPT_NUM gets value of
parameter D_ID. The active set is created based on DEPTID = DEPT_NUM.
Then, the cursor loop prints all employees for department number 10. The parameter
can be passed a value with a literal (as done in here), a bind variable, or an expression.
SQL>
A cursor with a parameter can be opened multiple times with a different parameter
value to get a different active set.
When you declare a cursor with one or more parameters, you can initialize it
to a default value as follows:
CURSOR employee_cur (dept_id employee.DeptId%TYPE := 99) IS
An explicit cursor is the name of the work area for an active set. A cursor variable is
a reference to the work area. A cursor is based on one specific query, whereas a cur-
sor variable can be opened with different queries within a program. A static cursor
is like a constant, and a cursor variable is like a pointer to that cursor. You can also
use the action statements OPEN, FETCH, and CLOSE with cursor variables. The
cursor attributes %ISOPEN, %FOUND, %NOTFOUND, and %ROWCOUNT
are available for cursor variables. Cursor variables have many similarities with stat-
ic cursors.
The cursor variable has other capabilities in addition to the features of a static
cursor. It is a variable, so it can be used in an assignment statement. A cursor vari-
able can also be assigned to another cursor variable.
Two steps are involved in creating a cursor variable. First, you have to create a ref-
erenced cursor type. Second, you have to declare an actual cursor variable with the
referenced cursor type. The general syntax is
where cursortypename is the name of the type of cursor. The RETURN clause is op-
tional. The returntype is the RETURN data type and can be any valid data structure,
such as a record or structure defined with %ROWTYPE. For example,
In this example, the first cursor type, any_cursor_type, is called the weak type,
because its RETURN clause is missing. This type of cursor type can be used with
any query. The cursor type declared with the RETURN clause is called the strong
type, because it links a row type to the cursor type at the declaration time.
ShahCh12v3.qxd 4/16/04 12:01 PM Page 280
You assign a cursor to the cursor variable when you OPEN it. The general syntax is
OPEN cursorname / cursorvarname FOR SELECT query;
If the cursor type is declared with the RETURN clause, the structure from the SE-
LECT query must match the structure specified in the REF CURSOR declaration.
For example,
OPEN employee_cursor_var FOR SELECT * FROM employee;
The structure returned by the SELECT query matches the RETURN type employ-
ee%ROWTYPE.
The other cursor type, any_cursor_type, is declared without the RETURN
clause. It can be opened without any worry about matching the query’s result to
anything. The weak type is more flexible than the strong type, but there is no error
checking. Let us look at some OPEN statements for the weak cursor variable:
OPEN any_cursor_var FOR SELECT * FROM dept;
OPEN any_cursor_var FOR SELECT * FROM employee;
OPEN any_cursor_var FOR SELECT DeptId FROM dept;
It is possible to have all three statements in one program block. The cursor variable
assumes different structures with each OPEN.
The fetching action is same as that of a cursor. The compiler checks the data struc-
ture type after the INTO clause to see if it matches the query linked to the cursor.
The general syntax is
FETCH cursorvarname INTO recordname / variablelist;
(Note: At the end of this chapter, under More Sample Programs, are three more
coding examples on cursors.)
EXCEPTIONS
task, however. A programmer must think of all the negative situations that may arise
while the program is executed. For example, the system might run out of memory, the
database might not be accessible, or the user might type in the wrong value or press
the wrong key. The programmer must put extra effort into program design to remove
bugs and make the program error-proof with additional code to perform in case of
exceptions. PL/SQL provides ways to trap and handle errors, and it is possible to cre-
ate PL/SQL programs with full protection against errors. When exception-handling
code is written for an exception, that exception can occur anywhere in the block, and
the same handler can deal with it.
The syntax of an anonymous block is given below. Control transfers from the
execution section to the exception section. PL/SQL browses through the section to
look for the handler. If the handler is present, it is executed. The program may have
more than one exception handler, written with WHEN . . . THEN statements like an
ELSIF or CASE structure (as supported by Oracle9i). For example,
DECLARE
Declaration of constants, variables, cursors, and exceptions
BEGIN
/* Exception is raised here.*/
EXCEPTION
/* Exception is trapped here.*/
END;
EXCEPTION
WHEN exceptionname1 [OR exceptionname2, . . .] THEN
Executable statements
[WHEN exceptionname3 [OR exceptionname4, . . .] THEN
Executable statements]
[WHEN OTHERS THEN
Executable statements]
An exception is handled when the exception name matches the name of the
raised exception. The exceptions are trapped by name. If an exception is raised but
no handler for it is present, the WHEN OTHERS clause is performed (if present). If
there is no handler for an exception and no WHEN OTHERS clause, the error
number and associated message are displayed to the user.
TYPES OF EXCEPTIONS
There are approximately 20 such exceptions. Each has a name and associ-
ated error number.
2. Nonpredefined Oracle server exceptions are standard Oracle server er-
rors that are not named by the system. They can be declared in the decla-
ration section but are raised implicitly by the server. These exceptions do
not have a name, but they do have an associated error number.
3. User-defined exceptions are exceptions that are declared in the declara-
tion section and are raised by the user explicitly. The user decides which
abnormal condition is an exception. The Oracle server does not consider
these conditions to be errors.
Exceptions that are given names by PL/SQL are declared in a PL/SQL package
called STANDARD. The exception-handling routine is also defined there. The user
does not have to declare or raise predefined server exceptions. Figure 12-7 provides
the exception name, the error code returned by the built-in function SQLCODE,
and a brief description of the exception.
A nonpredefined Oracle server exception has an attached Oracle error code, but it is
not named by Oracle. You can trap such exceptions with a WHEN OTHERS clause
or by declaring them with names in the DECLARE section. The declared exception
ShahCh12v3.qxd 4/16/04 12:01 PM Page 284
SQL> /
Enter value for department_id: 50
NO SUCH DEPARTMENT WITH EMPLOYEES
SQL> /
Enter value for department_id: 40
Houston, Larry
SQL>
is raised implicitly by Oracle, or you can raise it explicitly. You can write exception-
handler code for it.
exceptionname EXCEPTION;
PRAGMA EXCEPTION_INIT (exceptionname, errornumber);
SQL> DECLARE
2 emp_remain EXCEPTION;
3 PRAGMA EXCEPTION_INIT (emp_remain, -2292);
4 v_deptid dept.DeptId%TYPE := &p_deptnum;
5 BEGIN
6 DELETE FROM dept
7 WHERE DeptId = v_deptid;
8 COMMIT;
9 EXCEPTION
10 WHEN emp_remain THEN
11 DBMS_OUTPUT.PUT(’DEPARTMENT ’ || TO_CHAR(v_deptid));
12 DBMS_OUTPUT.PUT(’ cannot be removed - ’);
13 DBMS_OUTPUT.PUT_LINE(’Employees in department’);
14 END;
15 /
Enter value for p_deptnum: 10
DEPARTMENT 10 cannot be removed - Employees in department
SQL> /
Enter value for p_deptnum: 60
SQL>
Figure 12-11 shows the use of SQLCODE and SQLERRM to identify the
error code and message for further modifications of the exception section of a pro-
gram based on information displayed.
ShahCh12v3.qxd 4/16/04 12:01 PM Page 286
SQL> DECLARE
2 V_FIRST EMPLOYEE.FNAME%TYPE;
3 V_LAST EMPLOYEE.LNAME%TYPE;
4 D_ID NUMBER(2) := &DEPARTMENT_ID;
5 V_CODE NUMBER;
6 V_MSG VARCHAR2(255);
7 BEGIN
8 SELECT LNAME, FNAME
9 INTO V_LAST, V_FIRST
10 FROM EMPLOYEE
11 WHERE DEPTID = D_ID;
12 DBMS_OUTPUT.PUT_LINE(’ ’);
13 DBMS_OUTPUT.PUT_LINE(V_LAST || ’, ’ || V_FIRST);
14 EXCEPTION
15 WHEN OTHERS THEN
16 V_CODE := SQLCODE;
17 V_MSG := SQLERRM;
18 DBMS_OUTPUT.PUT_LINE(’ERROR CODE: ’ || SQLCODE);
19 DBMS_OUTPUT.PUT_LINE(SQLERRM);
20 END;
21 /
Enter value for department_id: 10
ERROR CODE: -1422
ORA-01422: exact fetch returns more than requested number of rows
SQL>
User-Defined Exceptions
The standard errors covered under the previous two types are in the STANDARD
package with an error code and an accompanying message. Often, however, you will
encounter situations that are specific to a given program. For example, a birth date
falls in the future, a quantity in an invoice is negative, a student registers for course
without satisfying prerequisite, and so on.
You are allowed to define your exceptions in PL/SQL. You must perform
three steps for exceptions you want to define:
SQL> DECLARE
2 invalid_commission EXCEPTION;
3 no_commission EXCEPTION;
4 v_comm employee.Commission%TYPE;
5 BEGIN
6 SELECT Commission
7 INTO v_comm
8 FROM employee
9 WHERE EmployeeId = &emp_id;
10 IF v_comm < 0 then
11 RAISE invalid_commission;
12 ELSIF v_comm IS NULL THEN
13 RAISE no_commission;
14 ELSE
15 DBMS_OUTPUT.PUT_LINE(TO_CHAR(v_comm));
16 END IF;
17 EXCEPTION
18 WHEN invalid_commission THEN
19 DBMS_OUTPUT.PUT_LINE(’Commission is negative.’);
20 WHEN no_commission THEN
21 DBMS_OUTPUT.PUT_LINE(’No commission value’);
22 WHEN OTHERS THEN
23 DBMS_OUTPUT.PUT_LINE(’No such ID’);
24 END;
25 /
RAISE_APPLICATION_ERROR Procedure
where the error_code is a user-specified number between - 20,000 and - 20,999 and
error_message is a user-supplied message that can be up to 512 bytes long. The third
Boolean parameter, TRUE/FALSE, is optional. TRUE means “place the error on
ShahCh12v3.qxd 4/16/04 12:01 PM Page 288
SQL> /
Enter value for emp_id: 123
No commission value
SQL> /
Enter value for emp_id: 546
Commission is negative.
SQL> /
Enter value for emp_id: 321
No such ID
SQL>
stack of other errors.” FALSE is the default value, and it replaces all previous errors.
For example,
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR
(–20001, ‘Department does not exist’);
In a Nutshell . . . 289
The RAISE statement is very much like the GOTO statement. They both
branch to another part of the program. The difference is that the RAISE statement
branches to the exception section, whereas the GOTO statement branches to an-
other statement in an executable block.
In this section, you will see the PL/SQL blocks based on the topics covered in this
chapter, such as an explicit cursor, a cursor FOR loop, a cursor with parameters,
and exception handling. The code in Figure 12-14 uses an explicit cursor emp_cur.
The active set contains the employee’s last name, first name, salary, and commis-
sion. The WHILE loop is used to work with one row at a time. Within the loop, an
employee’s salary and commission are added together to find the total income.
Also, note the use of a single-row function NVL in case the commission value is
NULL. Finally, total company wages (the total of all employee salaries and com-
missions) are printed.
When the program in Figure 12-15 is executed, you will be prompted to enter
the date for the substitution variable p_date. When the cursor is opened with v_date
as a parameter, it will retrieve rows that have HireDate after the inputted date. The
information for those employees will be printed. The program also will display the
total number of employees selected.
The program in Figure 12-16 selects employees with PositionId of 2 who are
managers. It locks those rows for future update. Using a cursor FOR loop, each
manager’s salary is modified to give a 7% raise. The WHERE CURRENT OF
clause is used to modify the current row fetched. The rows are released with the
COMMIT command.
The program in Figure 12-17 displays two customized prompts for an employ-
ee’s ID and the percentage increment/raise. First, rows are locked with the FOR
UPDATE clause. The UPDATE statement changes the salary if the ID is correct. If
the employee ID does not exist, a standard exception is raised implicitly. The excep-
tion is handled by displaying an appropriate message.
IN A NUTSHELL . . .
● A cursor is a private work area to store a statement and its active set.
● A static cursor’s contents are known at compile time, and a dynamic cursor
uses a cursor variable, which can refer to different SQL statements at differ-
ent times.
● An implicit cursor is declared, managed, and closed by PL/SQL.
● The programmer declares an explicit cursor for a PL/SQL block that returns
more than one row from the table.