Oracle PL/SQL – Control Structures

Subject: Information Technology – Database Systems
Grade: 12th Grade – HTL Computer Science
Prerequisites: PL/SQL Introduction, anonymous block, variables
Author: HTL Pinkafeld – IF/IT



1. IF – Simple Branching

1.1 Syntax

IF condition THEN
    -- Statements executed if condition is TRUE
END IF;

1.2 Example

DECLARE
    v_sal emp.sal%TYPE;
BEGIN
    SELECT sal INTO v_sal FROM emp WHERE empno = 7369;

    IF v_sal < 1500 THEN
        DBMS_OUTPUT.PUT_LINE('Salary below 1500 – Level: Entry');
    END IF;
END;
/

1.3 IF–ELSE

DECLARE
    v_grade NUMBER := 3;
BEGIN
    IF v_grade <= 2 THEN
        DBMS_OUTPUT.PUT_LINE('Passed with distinction');
    ELSE
        DBMS_OUTPUT.PUT_LINE('Passed');
    END IF;
END;
/

2. IF–ELSIF–ELSE / END IF – Multiple Branching

2.1 Syntax

IF condition1 THEN
    ...
ELSIF condition2 THEN
    ...
ELSIF condition3 THEN
    ...
ELSE
    ...
END IF;

Attention: Oracle uses ELSIF (not ELSEIF!)

2.2 Example: Grade Assessment

DECLARE
    v_points  NUMBER := 78;
    v_grade   NUMBER;
    v_text    VARCHAR2(20);
BEGIN
    IF    v_points >= 91 THEN v_grade := 1; v_text := 'Excellent';
    ELSIF v_points >= 76 THEN v_grade := 2; v_text := 'Good';
    ELSIF v_points >= 61 THEN v_grade := 3; v_text := 'Satisfactory';
    ELSIF v_points >= 51 THEN v_grade := 4; v_text := 'Sufficient';
    ELSE                       v_grade := 5; v_text := 'Insufficient';
    END IF;

    DBMS_OUTPUT.PUT_LINE(v_points || ' pts → Grade ' || v_grade || ' (' || v_text || ')');
END;
/

2.3 NULL in Conditions

When a variable is NULL, any comparison with it is NULL (neither TRUE nor FALSE):

DECLARE
    v_x NUMBER := NULL;
BEGIN
    IF v_x = 5 THEN         -- NULL = 5 → NULL → branch NOT executed
        DBMS_OUTPUT.PUT_LINE('Equal to 5');
    ELSIF v_x IS NULL THEN   -- Correct way to check for NULL
        DBMS_OUTPUT.PUT_LINE('v_x is NULL');
    END IF;
END;
/

3. CASE – Selection

3.1 Simple CASE

Compares an expression against concrete values:

DECLARE
    v_day  NUMBER := TO_NUMBER(TO_CHAR(SYSDATE, 'D')); -- 1=Sunday, 2=Monday ...
    v_name VARCHAR2(20);
BEGIN
    CASE v_day
        WHEN 1 THEN v_name := 'Sunday';
        WHEN 2 THEN v_name := 'Monday';
        WHEN 3 THEN v_name := 'Tuesday';
        WHEN 4 THEN v_name := 'Wednesday';
        WHEN 5 THEN v_name := 'Thursday';
        WHEN 6 THEN v_name := 'Friday';
        WHEN 7 THEN v_name := 'Saturday';
        ELSE         v_name := 'Unknown';
    END CASE;

    DBMS_OUTPUT.PUT_LINE('Today is ' || v_name);
END;
/

3.2 Searched CASE

Each WHEN clause contains its own condition:

DECLARE
    v_salary NUMBER := 4500;
    v_class  VARCHAR2(20);
BEGIN
    CASE
        WHEN v_salary < 2000 THEN v_class := 'Low';
        WHEN v_salary < 4000 THEN v_class := 'Medium';
        WHEN v_salary < 7000 THEN v_class := 'High';
        ELSE                       v_class := 'Very high';
    END CASE;

    DBMS_OUTPUT.PUT_LINE('Salary class: ' || v_class);
END;
/

3.3 CASE as Expression (in SQL)

SELECT ename,
       sal,
       CASE
           WHEN sal < 1500 THEN 'Junior'
           WHEN sal < 3000 THEN 'Professional'
           ELSE                  'Senior'
       END AS salary_class
FROM   emp
ORDER  BY sal;

4. Simple LOOP

4.1 Syntax

LOOP
    -- Statements
    EXIT WHEN condition;  -- or: EXIT (unconditional)
END LOOP;

4.2 Example: Multiplication Table

DECLARE
    v_i    NUMBER := 1;
    v_base NUMBER := 7;
BEGIN
    LOOP
        DBMS_OUTPUT.PUT_LINE(v_base || ' × ' || v_i || ' = ' || (v_base * v_i));
        v_i := v_i + 1;
        EXIT WHEN v_i > 10;
    END LOOP;
END;
/

4.3 Avoid Infinite Loops

Without EXIT WHEN, the loop runs forever! Always define an exit condition:

-- DANGEROUS – runs forever:
LOOP
    NULL;  -- no EXIT!
END LOOP;

-- CORRECT:
LOOP
    v_i := v_i + 1;
    EXIT WHEN v_i > 100;
END LOOP;

5. WHILE Loop

5.1 Syntax

WHILE condition LOOP
    -- Statements (executed as long as condition is TRUE)
END LOOP;

The condition is checked before each iteration. If FALSE on the first check, the block never executes.

5.2 Example: Calculate Factorial

DECLARE
    v_n       NUMBER := 10;
    v_fact    NUMBER := 1;
    v_counter NUMBER := 1;
BEGIN
    WHILE v_counter <= v_n LOOP
        v_fact    := v_fact * v_counter;
        v_counter := v_counter + 1;
    END LOOP;

    DBMS_OUTPUT.PUT_LINE(v_n || '! = ' || v_fact);
END;
/

5.3 Comparison: LOOP vs. WHILE

Feature Simple LOOP WHILE
Check time At end (EXIT WHEN) At start
Minimum iterations 1 0
Typical use When at least one iteration is certain When 0 iterations possible

6. Numeric FOR Loop

6.1 Syntax

FOR counter IN [REVERSE] lower_bound..upper_bound LOOP
    -- Statements
END LOOP;

The counter variable is automatically declared and managed. No need to declare it in the DECLARE section!

6.2 Forward and Reverse

BEGIN
    -- Forward: 1, 2, 3, 4, 5
    FOR i IN 1..5 LOOP
        DBMS_OUTPUT.PUT(i || ' ');
    END LOOP;
    DBMS_OUTPUT.NEW_LINE;

    -- Reverse: 5, 4, 3, 2, 1
    FOR i IN REVERSE 1..5 LOOP
        DBMS_OUTPUT.PUT(i || ' ');
    END LOOP;
    DBMS_OUTPUT.NEW_LINE;
END;
/

6.3 Example: Compound Interest Table

DECLARE
    v_capital    NUMBER := 10000;
    v_rate       NUMBER := 0.035;  -- 3.5%
BEGIN
    DBMS_OUTPUT.PUT_LINE('Year | Capital');
    DBMS_OUTPUT.PUT_LINE('-----|--------');
    FOR year IN 1..10 LOOP
        v_capital := v_capital * (1 + v_rate);
        DBMS_OUTPUT.PUT_LINE(
            LPAD(year, 4) || ' | ' || TO_CHAR(v_capital, 'FM999,990.00') || ' USD'
        );
    END LOOP;
END;
/

7. Cursor FOR Loop (Preview)

The cursor FOR loop (fully covered in the "Cursors" chapter) automatically iterates over all rows of a query:

BEGIN
    FOR r IN (SELECT ename, sal FROM emp WHERE deptno = 20 ORDER BY sal DESC) LOOP
        DBMS_OUTPUT.PUT_LINE(r.ename || ': ' || r.sal);
    END LOOP;
END;
/

Advantage: No explicit OPEN/FETCH/CLOSE needed – PL/SQL handles this automatically.


8. EXIT and CONTINUE

8.1 EXIT – Leave the Loop Immediately

DECLARE
    v_sum NUMBER := 0;
BEGIN
    FOR i IN 1..1000 LOOP
        v_sum := v_sum + i;
        EXIT WHEN v_sum > 100;  -- Stop as soon as sum > 100
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('Sum: ' || v_sum);
END;
/

8.2 CONTINUE – Skip Current Iteration

CONTINUE jumps directly to the next loop iteration (from Oracle 11g):

BEGIN
    FOR i IN 1..10 LOOP
        CONTINUE WHEN MOD(i, 2) = 0;  -- Skip even numbers
        DBMS_OUTPUT.PUT(i || ' ');    -- Only odd: 1 3 5 7 9
    END LOOP;
    DBMS_OUTPUT.NEW_LINE;
END;
/

8.3 Nested Loops with Labels

Labels allow targeted exit from an outer loop:

BEGIN
    <<outer_loop>>
    FOR i IN 1..5 LOOP
        FOR j IN 1..5 LOOP
            EXIT outer_loop WHEN i = 3 AND j = 3;  -- Exit both loops
            DBMS_OUTPUT.PUT('(' || i || ',' || j || ') ');
        END LOOP;
        DBMS_OUTPUT.NEW_LINE;
    END LOOP outer_loop;
    DBMS_OUTPUT.PUT_LINE('Done.');
END;
/

9. GOTO and Labels

9.1 GOTO (Use with Caution)

GOTO jumps to a label in the same block. Can make code hard to read – useful in exceptional cases:

DECLARE
    v_i NUMBER := 1;
BEGIN
    <<loop_start>>
    IF v_i <= 5 THEN
        DBMS_OUTPUT.PUT_LINE('Iteration: ' || v_i);
        v_i := v_i + 1;
        GOTO loop_start;
    END IF;
END;
/

Recommendation: Avoid GOTO if possible, use structured loops instead.

9.2 NULL Statement as Placeholder

NULL is a legal statement that does nothing. Useful as a placeholder:

BEGIN
    IF 1 = 2 THEN
        NULL;  -- Intentionally empty – syntactically required
    END IF;
END;
/

10. Summary and Outlook

10.1 Overview of Control Structures

Structure Purpose Syntax
IF ... END IF Simple branching IF b THEN ... END IF
IF ... ELSIF ... ELSE Multiple branching IF b1 THEN ... ELSIF b2 THEN ...
CASE ... END CASE Multiple selection CASE x WHEN v THEN ...
LOOP ... END LOOP Conditional loop with EXIT WHEN
WHILE ... LOOP Pre-tested loop checks before each iteration
FOR i IN a..b Count loop counter automatically managed
CONTINUE Skip iteration from Oracle 11g
EXIT Leave loop with or without condition

10.2 Common Mistakes

Error Problem
ELSEIF instead of ELSIF Syntax error – Oracle only knows ELSIF
Declaring FOR counter in DECLARE FOR counter is implicit – redeclaration causes conflict
Missing END IF / END LOOP Syntax error
Forgetting NULL in condition IF x = NULL is never TRUE – use IS NULL!

10.3 Outlook

The next chapter covers Cursors – the ability to process multiple rows from a SQL query row by row:

Previous TopicIntroduction & Basics Next TopicCursors