Você está na página 1de 14

FLOW CONTROL IN PL/SQL

Examples of simple pl sql

DECLARE
numerator NUMBER;
denominator NUMBER;
the_ratio NUMBER;
lower_limit CONSTANT NUMBER := 0.72;
samp_num CONSTANT NUMBER := 132;
BEGIN
SELECT x, y INTO numerator, denominator FROM result_table
WHERE sample_id = samp_num;
the_ratio := numerator/denominator;
IF the_ratio > lower_limit THEN
INSERT INTO ratio VALUES (samp_num, the_ratio);
ELSE
INSERT INTO ratio VALUES (samp_num, -1);
END IF;
COMMIT;
EXCEPTION
WHEN ZERO_DIVIDE THEN
INSERT INTO ratio VALUES (samp_num, 0);
COMMIT;
WHEN OTHERS THEN
ROLLBACK;
END;

2)SELECT * FROM temp ORDER BY col1;

NUM_COL1 NUM_COL2 CHAR_COL


-------- -------- ---------
1 100 i is odd
2 200 i is even
3 300 i is odd
4 400 i is even
5 500 i is odd
6 600 i is even
7 700 i is odd
8 800 i is even
9 900 i is odd
10 1000 i is even

DECLARE
x NUMBER := 100;
BEGIN
FOR i IN 1..10 LOOP
IF MOD(i,2) = 0 THEN -- i is even
INSERT INTO temp VALUES (i, x, 'i is even');
ELSE
INSERT INTO temp VALUES (i, x, 'i is odd');
END IF;
x := x + 100;
END LOOP;
COMMIT;
END;

SQL> SELECT ename, empno, sal FROM emp ORDER BY sal DESC;

ENAME EMPNO SAL


---------- --------- --------
KING 7839 5000
SCOTT 7788 3000
FORD 7902 3000
JONES 7566 2975
BLAKE 7698 2850
CLARK 7782 2450
ALLEN 7499 1600
TURNER 7844 1500
MILLER 7934 1300
WARD 7521 1250
MARTIN 7654 1250
ADAMS 7876 1100
JAMES 7900 950
SMITH 7369 800

PL/SQL Block
-- available online in file 'sample2'
DECLARE
CURSOR c1 is
SELECT ename, empno, sal FROM emp
ORDER BY sal DESC; -- start with highest paid employee
my_ename VARCHAR2(10);
my_empno NUMBER(4);
my_sal NUMBER(7,2);
BEGIN
OPEN c1;
FOR i IN 1..5 LOOP
FETCH c1 INTO my_ename, my_empno, my_sal;
EXIT WHEN c1%NOTFOUND; /* in case the number requested */
/* is more than the total */
/* number of employees */
INSERT INTO temp VALUES (my_sal, my_empno, my_ename);
COMMIT;
END LOOP;
CLOSE c1;
END;

Output Table
SQL> SELECT * FROM temp ORDER BY col1 DESC;
NUM_COL1 NUM_COL2 CHAR_COL
-------- -------- --------
5000 7839 KING
3000 7902 FORD
3000 7788 SCOTT
2975 7566 JONES
2850 7698 BLAKE

3) DECLARE
x NUMBER := 0;
counter NUMBER := 0;
BEGIN
FOR i IN 1..4 LOOP
x := x + 1000;
counter := counter + 1;
INSERT INTO temp VALUES (x, counter, 'in OUTER loop');
/* start an inner block */
DECLARE
x NUMBER := 0; -- this is a local version of x
BEGIN
FOR i IN 1..4 LOOP
x := x + 1; -- this increments the local x
counter := counter + 1;
INSERT INTO temp VALUES (x, counter, 'inner loop');
END LOOP;
END;
END LOOP;
COMMIT;
END;

Output Table
SQL> SELECT * FROM temp ORDER BY col2;

NUM_COL1 NUM_COL2 CHAR_COL


-------- -------- -------------
1000 1 in OUTER loop
1 2 inner loop
2 3 inner loop
3 4 inner loop
4 5 inner loop
2000 6 in OUTER loop
1 7 inner loop
2 8 inner loop
3 9 inner loop
4 10 inner loop
3000 11 in OUTER loop
1 12 inner loop
2 13 inner loop
3 14 inner loop
4 15 inner loop
4000 16 in OUTER loop
1 17 inner loop
2 18 inner loop
3 19 inner loop
4 20 inner loop

4) DECLARE
qty_on_hand NUMBER(5);
BEGIN
SELECT quantity INTO qty_on_hand FROM inventory
WHERE product = 'TENNIS RACKET'
FOR UPDATE OF quantity;
IF qty_on_hand > 0 THEN -- check quantity
UPDATE inventory SET quantity = quantity - 1
WHERE product = 'TENNIS RACKET';
INSERT INTO purchase_record
VALUES ('Tennis racket purchased', SYSDATE);
ELSE
INSERT INTO purchase_record
VALUES ('Out of tennis rackets', SYSDATE);
END IF;
COMMIT;
END;

5)DECLARE
my_sal REAL(7,2);
PROCEDURE adjust_salary (emp_id INT, salary IN OUT REAL) IS ...
BEGIN
SELECT AVG(sal) INTO my_sal FROM emp;
adjust_salary(7788, my_sal); -- assigns a new value to my_sal

5) DECLARE
qty_on_hand NUMBER(5);
BEGIN
SELECT quantity INTO qty_on_hand FROM inventory
WHERE product = 'TENNIS RACKET'
FOR UPDATE OF quantity;
IF qty_on_hand > 0 THEN -- check quantity
UPDATE inventory SET quantity = quantity - 1
WHERE product = 'TENNIS RACKET';
INSERT INTO purchase_record
VALUES ('Tennis racket purchased', SYSDATE);
ELSE
INSERT INTO purchase_record
VALUES ('Out of tennis rackets', SYSDATE);
END IF;
COMMIT;
END;
6) SET SERVEROUTPUT ON

DECLARE
l_day VARCHAR2(10);
BEGIN
l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));

IF l_day IN ('SATURDAY', 'SUNDAY') THEN


DBMS_OUTPUT.put_line('It''s the weekend!');
ELSE
DBMS_OUTPUT.put_line('It''s not the weekend yet!');
END IF;
END;
/

7)
SET SERVEROUTPUT ON
DECLARE
l_day VARCHAR2(10);
BEGIN
l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));

IF l_day = 'SATURDAY' THEN


DBMS_OUTPUT.put_line('The weekend has just started!');
ELSIF l_day = 'SUNDAY' THEN
DBMS_OUTPUT.put_line('The weekend is nearly over!');
ELSE
DBMS_OUTPUT.put_line('It''s not the weekend yet!');
END IF;
END;
/

8) SET SERVEROUTPUT ON

DECLARE
l_day VARCHAR2(10);
BEGIN
l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));

CASE l_day
WHEN 'SATURDAY' THEN
DBMS_OUTPUT.put_line('The weekend has just started!');
WHEN 'SUNDAY' THEN
DBMS_OUTPUT.put_line('The weekend is nearly over!');
ELSE
DBMS_OUTPUT.put_line('It''s not the weekend yet!');
END CASE;
END;
/
9) SET SERVEROUTPUT ON

DECLARE
l_day VARCHAR2(10);
BEGIN
l_day := TRIM(TO_CHAR(SYSDATE, 'DAY'));

CASE
WHEN l_day = 'SATURDAY' THEN
DBMS_OUTPUT.put_line('The weekend has just started!');
WHEN l_day = 'SUNDAY' THEN
DBMS_OUTPUT.put_line('The weekend is nearly over!');
ELSE
DBMS_OUTPUT.put_line('It''s not the weekend yet!');
END CASE;
END;
/
10) SET SERVEROUTPUT ON

DECLARE
i NUMBER := 1;
BEGIN
LOOP
EXIT WHEN i > 5;
DBMS_OUTPUT.put_line(i);
i := i + 1;
END LOOP;
END;
/
11) SET SERVEROUTPUT ON

BEGIN
FOR i IN 1 .. 5 LOOP
DBMS_OUTPUT.put_line(i);
END LOOP;
END;
/
12) SET SERVEROUTPUT ON

DECLARE
i NUMBER := 1;
BEGIN
WHILE i <= 5 LOOP
DBMS_OUTPUT.put_line(i);
i := i + 1;
END LOOP;
END;
/

GOTO
The GOTO statement allows a program to branch unconditionally to a predefined label. The
following example uses the GOTO statement to repeat the functionality of the examples in the
previous section.

SET SERVEROUTPUT ON
DECLARE
i NUMBER := 1;
BEGIN
LOOP
IF i > 5 THEN
GOTO exit_from_loop;
END IF;
DBMS_OUTPUT.put_line(i);
i := i + 1;
END LOOP;

<< exit_from_loop >>


NULL;
END;
/
A procedure is called as a PL/SQL statement. For example, the
procedure raise_salary might be called as follows:
raise_salary(emp_num, amount);

Inside a procedure, an IN parameter acts like a constant. So, you cannot assign it a
value. An OUT parameter acts like a local variable. So, you can change its value and
reference the value in any way. An IN OUT parameter acts like an initialized variable.
So, you can assign it a value, which can be assigned to another variable. For summary
information about the parameter modes, see Table 8-1.

Unlike OUT and IN OUT parameters, IN parameters can be initialized to default values.
For more information, see "Using Default Values for Subprogram Parameters".

Before exiting a procedure, explicitly assign values to all OUT formal parameters.
An OUT actual parameter can have a value before the subprogram is called. However,
when you call the subprogram, the value is lost unless you specify the compiler
hint NOCOPY or the subprogram exits with an unhandled exception.

You can write the procedure spec and body as a unit. Or, you can separate the
procedure spec from its body. That way, you can hide implementation details by
placing the procedure in a package. You can define procedures in a package body
without declaring their specs in the package spec. However, such procedures can be
called only from inside the package.

At least one statement must appear in the executable part of a procedure.


The NULL statement meets this requirement.

A procedure is a subprogram that performs a specific action. You write procedures


using the syntax:
[CREATE [OR REPLACE]]
PROCEDURE procedure_name[(parameter[, parameter]...)]
[AUTHID {DEFINER | CURRENT_USER}] {IS | AS}
[PRAGMA AUTONOMOUS_TRANSACTION;]
[local declarations]
BEGIN
executable statements
[EXCEPTION
exception handlers]
END [name];

Examples
The following procedure debits a bank account:
PROCEDURE debit_account (acct_id INTEGER, amount REAL) IS
old_balance REAL;
new_balance REAL;
overdrawn EXCEPTION;
BEGIN
SELECT bal INTO old_balance FROM accts WHERE acctno = acct_id;
new_balance := old_balance - amount;
IF new_balance < 0 THEN
RAISE overdrawn;
ELSE
UPDATE accts SET bal = new_balance WHERE acctno = acct_id;
END IF;
EXCEPTION
WHEN overdrawn THEN
...
END debit_account;

In the following example, you call the procedure using named notation:
debit_account(amount => 500, acct_id => 10261);

Consider the procedure raise_salary, which increases the salary of an employee by a


given amount:
PROCEDURE raise_salary (emp_id INTEGER, amount REAL) IS
current_salary REAL;
salary_missing EXCEPTION;
BEGIN
SELECT sal INTO current_salary FROM emp
WHERE empno = emp_id;
IF current_salary IS NULL THEN
RAISE salary_missing;
ELSE
UPDATE emp SET sal = sal + amount
WHERE empno = emp_id;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO emp_audit VALUES (emp_id, 'No such number');
WHEN salary_missing THEN
INSERT INTO emp_audit VALUES (emp_id, 'Salary is null');
END raise_salary;

PROCEDURE award_bonus (emp_id NUMBER) IS


bonus REAL;
comm_missing EXCEPTION;
BEGIN -- executable part starts here
SELECT comm * 0.15 INTO bonus FROM emp WHERE empno = emp_id;
IF bonus IS NULL THEN
RAISE comm_missing;
ELSE
UPDATE payroll SET pay = pay + bonus WHERE empno = emp_id;
END IF;
EXCEPTION -- exception-handling part starts here
WHEN comm_missing THEN
...
END award_bonus;
PROCEDURE award_bonus (emp_id NUMBER) IS
bonus REAL;
comm_missing EXCEPTION;
BEGIN -- executable part starts here
SELECT comm * 0.15 INTO bonus FROM emp WHERE empno = emp_id;
IF bonus IS NULL THEN
RAISE comm_missing;
ELSE
UPDATE payroll SET pay = pay + bonus WHERE empno = emp_id;
END IF;
EXCEPTION -- exception-handling part starts here
WHEN comm_missing THEN
...
END award_bonus;

2) CREATE OR REPLACE PROCEDURE display_numbers (


p_lower IN NUMBER,
p_upper IN NUMBER)
AS
BEGIN
FOR i IN p_lower .. p_upper LOOP
DBMS_OUTPUT.put_line(i);
END LOOP;
END;
/

SET SERVEROUTPUT ON
EXECUTE display_numbers(2, 6);
2
3
4
5
6

PL/SQL procedure successfully completed.

Functions

Understanding PL/SQL Functions


A function is a subprogram that computes a value. Functions and procedures are
structured alike, except that functions have a RETURN clause. You write (local)
functions using the syntax:
[CREATE [OR REPLACE ] ]
FUNCTION function_name [ ( parameter [ , parameter ]... ) ] RETURN
datatype
[ AUTHID { DEFINER | CURRENT_USER } ]
[ PARALLEL_ENABLE
[ { [CLUSTER parameter BY (column_name [, column_name ]... ) ] |
[ORDER parameter BY (column_name [ , column_name ]... ) ] } ]
[ ( PARTITION parameter BY
{ [ {RANGE | HASH } (column_name [, column_name]...)] | ANY }
) ]
]
[DETERMINISTIC] [ PIPELINED [ USING implementation_type ] ]
[ AGGREGATE [UPDATE VALUE] [WITH EXTERNAL CONTEXT]
USING implementation_type ] {IS | AS}
[ PRAGMA AUTONOMOUS_TRANSACTION; ]
[ local declarations ]
BEGIN
executable statements
[ EXCEPTION
exception handlers ]
END [ name ];

DETERMINISTIC
This hint helps the optimizer avoid redundant function calls.
IN, OUT, IN OUT
These parameter modes define the behavior of formal parameters. An IN parameter
lets you pass values to the subprogram being called. An OUT parameter lets you return
values to the caller of the subprogram. An IN OUT parameter lets you pass initial values
to the subprogram being called and return updated values to the caller.
The following function returns the balance of a specified bank account:
FUNCTION balance (acct_id INTEGER) RETURN REAL IS
acct_bal REAL;
BEGIN
SELECT bal INTO acct_bal FROM accts WHERE acctno = acct_id;
RETURN acct_bal;
END balance;

FUNCTION compound (
years NUMBER,
amount NUMBER,
rate NUMBER) RETURN NUMBER IS
BEGIN
RETURN amount * POWER((rate / 100) + 1, years);
END compound;

In a function, there must be at least one execution path that leads to


a RETURN statement. Otherwise, you get a function returned without value error at run
time.

2) CREATE OR REPLACE FUNCTION difference (

p_lower IN NUMBER,
p_upper IN NUMBER)
RETURN NUMBER
AS
BEGIN
RETURN p_upper - p_lower;
END;
/

VARIABLE l_result NUMBER


BEGIN
:l_result := difference(2, 6);
END;
/
PL/SQL procedure successfully completed.

PRINT l_result

L_RESULT
----------
4

Você também pode gostar