Control Flow Statements in PL SQL
Control Flow Statements in PL SQL
Part 2 in a series of articles on understanding and using PL/SQL for accessing Oracle
Database
PL/SQL is one of the core technologies at Oracle and is essential to leveraging the full
potential of Oracle Database. PL/SQL combines the relational data access capabilities of the
Structured Query Language with a flexible embedded procedural language, and it executes
complex queries and programmatic logic run inside the database engine itself. This enhances
the agility, efficiency, and performance of database-driven applications.
Steven Feuerstein, one of the industry’s best-respected and most prolific experts in PL/SQL,
wrote a 12-part tutorial series on the language. Those articles, first published in 2011, have
been among the most popular ever published on the Oracle website and continue to find new
readers and enthusiasts in the database community. Beginning with the first installment, the
entire series is being updated and republished; please enjoy!
There is one way in which PL/SQL is just like every other programming language you will ever
use: It (the PL/SQL runtime engine) does only exactly what you tell it to do. Each block of
PL/SQL code you write contains one or more statements implementing complex business
rules or processes. When you run a block of code, as either an anonymous block or a script
or by calling a stored program unit that contains all the logic, Oracle Database follows the
directions you specify in that block.
It is therefore critical to know how to specify which statements should be run, under what
circumstances, and with what frequency. To do this, Oracle Database offers conditional and
iterative constructs. This article introduces you to the IF statement, the CASE statement and
expression, and the various types of loops PL/SQL supports.
Conditional branching in code
Almost every piece of code you write will require conditional control, that is, the ability to
direct the flow of execution through your program, based on a condition. You do this with
IF-THEN-ELSE and CASE statements.
There are also CASE expressions; although not the same as CASE statements, they can
sometimes be used to eliminate the need for an IF or CASE statement altogether.
IF. The IF statement enables you to implement conditional branching logic in your programs.
With it, you’ll be able to implement requirements such as the following:
● If the salary is between $10,000 and $20,000, apply a bonus of $1,500.
● If the collection contains more than 100 elements, truncate it.
The IF statement comes in three flavors, as shown in Table 1. Let’s take a look at some
examples of IF statements.
IF Type Characteristics
This is the simplest form of the IF statement. The condition between IF and
IF THEN THEN determines whether the set of statements between THEN and END
END IF; IF should be executed. If the condition evaluates to FALSE or NULL, the
code will not be executed.
This last and most complex form of the IF statement selects a condition
F THEN that is TRUE from a series of mutually exclusive conditions and then
ELSIF executes the set of statements associated with that condition. If you’re
ELSE END writing IF statements like this in any Oracle Database release from
IF; Oracle9I Database Release 1 onward, you should consider using searched
CASE statements instead.
l_year sales_data%ROWTYPE;
BEGIN
OPEN years_cur;
LOOP
FETCH years_cur INTO l_year;
CLOSE years_cur;
END display_multiple_years;
The cursor FOR loop requires none of these steps; Oracle Database performs all steps (open,
fetch, terminate, close) implicitly.
Although a simple loop should not be used to fetch row by row through a cursor’s dataset,
it should be used when (1) you may need to conditionally exit from the loop (with an EXIT
statement) and (2) you want the body of the loop to execute at least once.
The WHILE loop. The WHILE loop is very similar to the simple loop; but a critical difference is
that it checks the termination condition up front. That is, a WHILE loop might not even
execute its body a single time. Listing 3 demonstrates the WHILE loop.
Code listing 3: A WHILE loop
Copy code snippet
Copied to Clipboard
Error: Could not Copy
Copied to Clipboard
Error: Could not Copy
PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
,end_year_in IN PLS_INTEGER
)
IS
l_current_year PLS_INTEGER := start_year_in;
BEGIN
WHILE (l_current_year <= end_year_in)
LOOP
display_total_sales (l_current_year);
l_current_year := l_current_year + 1;
END LOOP;
END display_multiple_years;
The WHILE loop consists of a condition (a Boolean expression) and a loop body. Before each
iteration of the body, Oracle Database evaluates the condition. If it evaluates to TRUE, the
loop body will execute. If it evaluates to FALSE or NULL, the loop will terminate.
You must then make sure to include code in the body of the loop that will affect the
evaluation of the condition—and, at some point, cause the loop to stop. In the procedure
in Listing 3, that code is
Copy code snippet
Copied to Clipboard
Error: Could not Copy
Copied to Clipboard
Error: Could not Copy
l_current_year := l_current_year + 1
In other words, move to the next year until the total sales for all specified years are
displayed.
If your WHILE loop does not somehow change the way the condition is evaluated, that loop
will never terminate.
One way in, one way out
In all the examples in the previous section, the FOR loop clearly requires the smallest
amount of code. Generally, you want to find the simplest, most readable implementation for
your requirements. Does that mean that you should always use a FOR loop? Not at all.
Using the FOR loop is the best solution for the scenario described because I needed to run
the body of the loop a fixed number of times. In many other situations, the number of times
a loop must execute will vary, depending on the state of the data in the application. You may
also need to terminate the loop when a certain condition has occurred; in this case, a FOR
loop is not a good fit.
One important and fundamental principle in structured programming is “one way in, one
way out”—that is, a program should have a single point of entry and a single point of exit. A
single point of entry is not an issue with PL/SQL—no matter what kind of loop you are using,
there is always only one entry point into the loop: the first executable statement following
the LOOP keyword. It is quite possible, however, to construct loops that have multiple exit
paths. Avoid this practice. Having multiple ways of terminating a loop results in code that is
much harder to debug and maintain than it would be otherwise.
In particular, you should follow these two guidelines for loop termination:
1. Do not use EXIT or EXIT WHEN statements within FOR and WHILE loops.
You should use a FOR loop only when you want to iterate through all the values (integer or
record) specified in the range. An EXIT inside a FOR loop disrupts this process and subverts
the intent of that structure. A WHILE loop, on the other hand, specifies its termination
condition in the WHILE statement itself.
Listing 4 presents an example of a FOR loop with a conditional exit. I want to display the
total sales for each year within the specified range. If I ever encounter a year with zero sales
(calculated by the total_sales_for_year function), however, I should stop the loop.
RETURN l_return;
END total_sales;
Note that the loop terminates in one of two ways: either by iterating through all integers
between the start and end years or by executing the RETURN inside the loop. In addition and
related to that, this function now has two instances of RETURN, which means that there are
two ways “out” of the function. This is also not a recommended way to design your
functions. You should have just a single RETURN in your executable section: the last line of
the function.
I can restructure this function so that both the loop and the function have just “one way
out,” as shown in Listing 7.
Code listing 7: A loop revision with one way out
Copy code snippet
Copied to Clipboard
Error: Could not Copy
Copied to Clipboard
Error: Could not Copy
FUNCTION total_sales (
start_year_in IN PLS_INTEGER
, end_year_in IN PLS_INTEGER)
RETURN PLS_INTEGER
IS
l_current_year PLS_INTEGER := start_year_in;
l_return PLS_INTEGER := 0;
BEGIN
WHILE (l_current_year <= end_year_in
AND total_sales_for_year (l_current_year) > 0)
LOOP
l_return := l_return + total_sales_for_year (l_current_year);
l_current_year := l_current_year + 1;
END LOOP;
RETURN l_return;
END total_sales;
All the logic required to terminate the loop is now in the WHILE condition, and after the loop
is finished, the function executes a single RETURN to send back the total sales value. This
second implementation is now simpler and easier to understand—and that is for a program
that itself is already quite simple. When you work with much more complex algorithms,
following the “one way in, one way out” guidelines will have an even greater impact on the
readability of your code.