Resources
Using Oracle PL/SQL
- Basic Structure of PL/SQL
- Variables and Types
- Simple PL/SQL Programs
- Control Flow in PL/SQL
- Cursors
- Procedures
- Discovering Errors
- Printing Variables
Basic Structure of PL/SQL
DECLARE /* Declarative section: variables, types, and local subprograms. */ BEGIN /* Executable section: procedural and SQL statements go here. */ /* This is the only section of the block that is required. */ EXCEPTION /* Exception handling section: error handling statements go here. */ END;
To execute a PL/SQL program, we must follow the program text itself by
- A line with a single dot ("."), and then
- A line with run;
Variables and Types
- One of the types used by SQL for database columns
- A generic type used in PL/SQL such as NUMBER
- Declared to be the same as the type of some database column
DECLARE price NUMBER; myBeer VARCHAR(20);
Types in PL/SQL can be tricky. In many cases, a PL/SQL variable will be used to manipulate data stored in a existing relation. In this case, it is essential that the variable have the same type as the relation column. If there is any type mismatch, variable assignments and comparisons may not work the way you expect. To be safe, instead of hard coding the type of a variable, you should use the %TYPE operator. For example:
DECLARE myBeer Beers.name%TYPE;
A variable may also have a type that is a record with several fields. The simplest way to declare such a variable is to use %ROWTYPE on a relation name. The result is a record type in which the fields have the same names and types as the attributes of the relation. For instance:
DECLARE beerTuple Beers%ROWTYPE;
The initial value of any variable, regardless of its type, is NULL. We can assign values to variables, using the ":=" operator. The assignment can occur either immediately after the type of the variable is declared, or anywhere in the executable portion of the program. An example:
DECLARE a NUMBER := 3; BEGIN a := a + 1; END; . run;
Simple Programs in PL/SQL
Notice we said "tuple" rather than "tuples", since the SELECT statement in PL/SQL only works if the result of the query contains a single tuple. The situation is essentially the same as that of the "single-row select" discussed in Section 7.1.5 of the text, in connection with embedded SQL. If the query returns more than one tuple, you need to use a cursor, as described in the next section. Here is an example:
CREATE TABLE T1( e INTEGER, f INTEGER ); DELETE FROM T1; INSERT INTO T1 VALUES(1, 3); INSERT INTO T1 VALUES(2, 4); /* Above is plain SQL; below is the PL/SQL program. */ DECLARE a NUMBER; b NUMBER; BEGIN SELECT e,f INTO a,b FROM T1 WHERE e>1; INSERT INTO T1 VALUES(b,a); END; . run;
Control Flow in PL/SQL
An IF statement looks like:
IF <condition> THEN <statement_list> ELSE <statement_list> END IF;
IF <condition_1> THEN ... ELSIF <condition_2> THEN ... ... ... ELSIF <condition_n> THEN ... ELSE ... END IF;
DECLARE a NUMBER; b NUMBER; BEGIN SELECT e,f INTO a,b FROM T1 WHERE e>1; IF b=1 THEN INSERT INTO T1 VALUES(b,a); ELSE INSERT INTO T1 VALUES(b+10,a+10); END IF; END; . run;
LOOP <loop_body> /* A list of statements. */ END LOOP;
EXIT WHEN <condition>;
DECLARE i NUMBER := 1; BEGIN LOOP INSERT INTO T1 VALUES(i,i); i := i+1; EXIT WHEN i>100; END LOOP; END; . run;
- EXIT by itself is an unconditional loop break. Use it inside a conditional if you like.
- A WHILE loop can be formed with
WHILE <condition> LOOP <loop_body> END LOOP;
- A simple FOR loop can be formed with:
FOR <var> IN <start>..<finish> LOOP <loop_body> END LOOP;
Here, <var> can be any variable; it is local to the for-loop and need not be declared. Also, <start> and <finish> are constants.
Cursors
The example below illustrates a cursor loop. It uses our example relation T1(e,f) whose tuples are pairs of integers. The program will delete every tuple whose first component is less than the second, and insert the reverse tuple into T1.
1) DECLARE /* Output variables to hold the result of the query: */ 2) a T1.e%TYPE; 3) b T1.f%TYPE; /* Cursor declaration: */ 4) CURSOR T1Cursor IS 5) SELECT e, f 6) FROM T1 7) WHERE e < f 8) FOR UPDATE; 9) BEGIN 10) OPEN T1Cursor; 11) LOOP /* Retrieve each row of the result of the above query into PL/SQL variables: */ 12) FETCH T1Cursor INTO a, b; /* If there are no more rows to fetch, exit the loop: */ 13) EXIT WHEN T1Cursor%NOTFOUND; /* Delete the current tuple: */ 14) DELETE FROM T1 WHERE CURRENT OF T1Cursor; /* Insert the reverse tuple: */ 15) INSERT INTO T1 VALUES(b, a); 16) END LOOP; /* Free cursor used by the query. */ 17) CLOSE T1Cursor; 18) END; 19) . 20) run;
- Line (1) introduces the declaration section.
- Lines (2) and (3) declare variables a and b to have types equal to the types of attributes e and f of the relation T1. Although we know these types are INTEGER, we wisely make sure that whatever types they may have are copied to the PL/SQL variables (compare with the previous example, where we were less careful and declared the corresponding variables to be of type NUMBER).
- Lines (4) through (8) define the cursor T1Cursor. It ranges over a relation defined by the SELECT-FROM-WHERE query. That query selects those tuples of T1 whose first component is less than the second component. Line (8) declares the cursor FOR UPDATE since we will modify T1 using this cursor later on Line (14). In general, FOR UPDATE is unnecessary if the cursor will not be used for modification.
- Line (9) begins the executable section of the program.
- Line (10) opens the cursor, an essential step.
- Lines (11) through (16) are a PL/SQL loop. Notice that such a loop is bracketed by LOOP and END LOOP. Within the loop we find:
- On Line (12), a fetch through the cursor into the local variables. In general, the FETCH statement must provide variables for each component of the tuple retrieved. Since the query of Lines (5) through (7) produces pairs, we have correctly provided two variables, and we know they are of the correct type.
- On Line (13), a test for the loop-breaking condition. Its meaning should be clear: %NOTFOUND after the name of a cursor is true exactly when a fetch through that cursor has failed to find any more tuples.
- On Line (14), a SQL DELETE statement that deletes the current tuple using the special WHERE condition CURRENT OF T1Cursor.
- On Line (15), a SQL INSERT statement that inserts the reverse tuple into T1.
- Line (17) closes the cursor.
- Line (18) ends the PL/SQL program.
- Lines (19) and (20) cause the program to execute.
Procedures
CREATE TABLE T2 ( a INTEGER, b CHAR(10) ); CREATE PROCEDURE addtuple1(i IN NUMBER) AS BEGIN INSERT INTO T2 VALUES(i, 'xxx'); END addtuple1; . run;
There can be any number of parameters, each followed by a mode and a type. The possible modes are IN (read-only), OUT (write-only), and INOUT (read and write). Note: Unlike the type specifier in a PL/SQL variable declaration, the type specifier in a parameter declaration must be unconstrained. For example, CHAR(10) and VARCHAR(20) are illegal; CHAR or VARCHAR should be used instead. The actual length of a parameter depends on the corresponding argument that is passed in when the procedure is invoked.
Following the arguments is the keyword AS (IS is a synonym). Then comes the body, which is essentially a PL/SQL block. We have repeated the name of the procedure after the END, but this is optional. However, the DECLARE section should not start with the keyword DECLARE. Rather, following AS we have:
... AS <local_var_declarations> BEGIN <procedure_body> END; . run;
BEGIN addtuple1(99); END; . run;
CREATE PROCEDURE addtuple2( x T2.a%TYPE, y T2.b%TYPE) AS BEGIN INSERT INTO T2(a, b) VALUES(x, y); END addtuple2; . run;
BEGIN addtuple2(10, 'abc'); END; . run;
CREATE TABLE T3 ( a INTEGER, b INTEGER ); CREATE PROCEDURE addtuple3(a NUMBER, b OUT NUMBER) AS BEGIN b := 4; INSERT INTO T3 VALUES(a, b); END; . run; DECLARE v NUMBER; BEGIN addtuple3(10, v); END; . run;
We can also write functions instead of procedures. In a function declaration, we follow the parameter list by RETURN and the type of the return value:
CREATE FUNCTION <func_name>(<param_list>) RETURN <return_type> AS ...
To find out what procedures and functions you have created, use the following SQL query:
select object_type, object_name from user_objects where object_type = 'PROCEDURE' or object_type = 'FUNCTION';
drop procedure <procedure_name>; drop function <function_name>;
Discovering Errors
show errors procedure <procedure_name>;
Note that the location of the error given as part of the error message is not always accurate!
Printing Variables
The steps are as follows:
- We declare a bind variable as follows:
VARIABLE <name> <type>
where the type can be only one of three things: NUMBER, CHAR, or CHAR(n). - We may then assign to the variable in a following PL/SQL statement, but we must prefix it with a colon.
- Finally, we can execute a statement
PRINT :<name>;
outside the PL/SQL statement
VARIABLE x NUMBER BEGIN :x := 1; END; . run; PRINT :x;
Sem comentários:
Enviar um comentário