<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://wiki.zcubes.com/index.php?action=history&amp;feed=atom&amp;title=Yurttas%2FPL%2FDBL%2Foracle%2FF%2FR%2For-plsql.html</id>
	<title>Yurttas/PL/DBL/oracle/F/R/or-plsql.html - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.zcubes.com/index.php?action=history&amp;feed=atom&amp;title=Yurttas%2FPL%2FDBL%2Foracle%2FF%2FR%2For-plsql.html"/>
	<link rel="alternate" type="text/html" href="http://wiki.zcubes.com/index.php?title=Yurttas/PL/DBL/oracle/F/R/or-plsql.html&amp;action=history"/>
	<updated>2026-04-28T05:51:46Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.35.2</generator>
	<entry>
		<id>http://wiki.zcubes.com/index.php?title=Yurttas/PL/DBL/oracle/F/R/or-plsql.html&amp;diff=82545&amp;oldid=prev</id>
		<title>MassBot1: Created page with &quot;=Using Oracle PL/SQL   ----=    * Basic Structure of PL/SQL  * yurttas/PL/DBL/oracle/F/R/#variables and types|Varia...&quot;</title>
		<link rel="alternate" type="text/html" href="http://wiki.zcubes.com/index.php?title=Yurttas/PL/DBL/oracle/F/R/or-plsql.html&amp;diff=82545&amp;oldid=prev"/>
		<updated>2013-11-05T05:35:29Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;=Using Oracle PL/SQL   ----=    * &lt;a href=&quot;/index.php?title=Yurttas/PL/DBL/oracle/F/R/&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Yurttas/PL/DBL/oracle/F/R/ (page does not exist)&quot;&gt;Basic Structure of PL/SQL&lt;/a&gt;  * yurttas/PL/DBL/oracle/F/R/#variables and types|Varia...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;=Using Oracle PL/SQL   ----=&lt;br /&gt;
&lt;br /&gt;
* [[yurttas/PL/DBL/oracle/F/R/#basic structure of pl/sql|Basic Structure of PL/SQL]]&lt;br /&gt;
* [[yurttas/PL/DBL/oracle/F/R/#variables and types|Variables and Types]]&lt;br /&gt;
* [[yurttas/PL/DBL/oracle/F/R/#simple programs in pl/sql|Simple PL/SQL Programs]]&lt;br /&gt;
* [[yurttas/PL/DBL/oracle/F/R/#control flow in pl/sql|Control Flow in PL/SQL]]&lt;br /&gt;
* [[yurttas/PL/DBL/oracle/F/R/#cursors|Cursors]]&lt;br /&gt;
* [[yurttas/PL/DBL/oracle/F/R/#procedures|Procedures]]&lt;br /&gt;
* [[yurttas/PL/DBL/oracle/F/R/#triggers|Triggers]]&lt;br /&gt;
* [[yurttas/PL/DBL/oracle/F/R/#errors|Discovering Errors]]&lt;br /&gt;
&lt;br /&gt;
===---- Basic Structure of PL/SQL===&lt;br /&gt;
&lt;br /&gt;
PL/SQL stands for Procedural Language/SQL. PL/SQL extends SQL by adding constructs found in procedural languages, resulting in a structural language that is more powerful than SQL. The basic unit in PL/SQL is a ''block''. All PL/SQL programs are made up of blocks, which can be nested within each other. Typically, each block performs a logical action in he program. A block has the following structure:&lt;br /&gt;
&lt;br /&gt;
     DECLARE&lt;br /&gt;
 &lt;br /&gt;
     /* Declarative section: variables, types, and local subprograms. */&lt;br /&gt;
 &lt;br /&gt;
     BEGIN&lt;br /&gt;
 &lt;br /&gt;
     /* Executable section: procedural and SQL statements go here. */&lt;br /&gt;
     /* This is the only section of the block that is required. */&lt;br /&gt;
 &lt;br /&gt;
     EXCEPTION&lt;br /&gt;
 &lt;br /&gt;
     /* Exception handling section: error handling statements go here. */&lt;br /&gt;
 &lt;br /&gt;
     END;&lt;br /&gt;
&lt;br /&gt;
Only the executable section is required. The other sections are optional. The only SQL statements allowed in a PL/SQL program are &amp;lt;tt&amp;gt;SELECT&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;INSERT&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;UPDATE&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;DELETE&amp;lt;/tt&amp;gt; and several other data manipulation statements plus some transaction control. However, the &amp;lt;tt&amp;gt;SELECT&amp;lt;/tt&amp;gt; statement has a special form in which a single tuple is placed in variables; more on this later. Data definition statements like &amp;lt;tt&amp;gt;CREATE&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;DROP&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;ALTER&amp;lt;/tt&amp;gt; are not allowed. The executable section also contains constructs such as assignments, branches, loops, procedure calls, and triggers, which are all described below. PL/SQL is not case sensitive. C style comments (&amp;lt;tt&amp;gt;/* ... */&amp;lt;/tt&amp;gt;) may be used.&lt;br /&gt;
&lt;br /&gt;
To execute a PL/SQL program, we must follow the program text itself by&lt;br /&gt;
&lt;br /&gt;
* A line with a single dot (&amp;quot;&amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt;&amp;quot;), and then&lt;br /&gt;
* A line with &amp;lt;tt&amp;gt;run;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As with Oracle SQL programs, we can invoke a PL/SQL program either by typing it in &amp;lt;tt&amp;gt;sqlplus&amp;lt;/tt&amp;gt; or by putting the code in a file and invoking the file in the various ways we learned in [[yurttas/PL/DBL/oracle/F/R/or-intro.html#executing sql from a file|Getting Started With Oracle]].&lt;br /&gt;
&lt;br /&gt;
===---- Variables and Types===&lt;br /&gt;
&lt;br /&gt;
Information is transmitted between a PL/SQL program and the database through ''variables''. Every variable has a specific type associated with it. That type can be&lt;br /&gt;
&lt;br /&gt;
* One of the types used by SQL for database columns&lt;br /&gt;
* A generic type used in PL/SQL such as &amp;lt;tt&amp;gt;NUMBER&amp;lt;/tt&amp;gt;&lt;br /&gt;
* Declared to be the same as the type of some database column&lt;br /&gt;
&lt;br /&gt;
The most commonly used generic type is &amp;lt;tt&amp;gt;NUMBER&amp;lt;/tt&amp;gt;. Variables of type &amp;lt;tt&amp;gt;NUMBER&amp;lt;/tt&amp;gt; can hold either an integer or a real number. The most commonly used character string type is &amp;lt;tt&amp;gt;VARCHAR(&amp;lt;/tt&amp;gt;''n''&amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt;, where ''n'' is the maximum length of the string in bytes. This length is required, and there is no default. For example, we might declare:&lt;br /&gt;
&lt;br /&gt;
 DECLARE&lt;br /&gt;
     price  NUMBER;&lt;br /&gt;
     myBeer VARCHAR(20);&lt;br /&gt;
&lt;br /&gt;
Types in PL/SQL are tricky. Certain SQL types cannot be parameterized in PL/SQL. For example, &amp;lt;tt&amp;gt;CHAR(50)&amp;lt;/tt&amp;gt; does not work, but either &amp;lt;tt&amp;gt;CHAR&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;VARCHAR(50)&amp;lt;/tt&amp;gt; works fine! Also note that PL/SQL allows &amp;lt;tt&amp;gt;BOOLEAN&amp;lt;/tt&amp;gt; variables, even though Oracle does not support &amp;lt;tt&amp;gt;BOOLEAN&amp;lt;/tt&amp;gt; as a type for database columns.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;tt&amp;gt;%TYPE&amp;lt;/tt&amp;gt; operator. For example:&lt;br /&gt;
&lt;br /&gt;
 DECLARE&lt;br /&gt;
     myBeer Beers.name%TYPE;&lt;br /&gt;
&lt;br /&gt;
gives PL/SQL variable &amp;lt;tt&amp;gt;myBeer&amp;lt;/tt&amp;gt; whatever type was declared for the &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; column in relation &amp;lt;tt&amp;gt;Beers&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
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 &amp;lt;tt&amp;gt;%ROWTYPE&amp;lt;/tt&amp;gt; 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:&lt;br /&gt;
&lt;br /&gt;
 DECLARE&lt;br /&gt;
     beerTuple Beers%ROWTYPE;&lt;br /&gt;
&lt;br /&gt;
makes variable &amp;lt;tt&amp;gt;beerTuple&amp;lt;/tt&amp;gt; be a record with fields &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;manufacture&amp;lt;/tt&amp;gt;, assuming that the relation has the schema &amp;lt;tt&amp;gt;Beers(name, manufacture)&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The initial value of any variable, regardless of its type, is &amp;lt;tt&amp;gt;NULL&amp;lt;/tt&amp;gt;. We can assign values to variables, using the &amp;quot;&amp;lt;tt&amp;gt;:=&amp;lt;/tt&amp;gt;&amp;quot; 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:&lt;br /&gt;
&lt;br /&gt;
 DECLARE&lt;br /&gt;
     a NUMBER := 3;&lt;br /&gt;
 BEGIN&lt;br /&gt;
     a := a + 1;&lt;br /&gt;
 END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
This program has no effect when run, because there are no changes to the database.&lt;br /&gt;
&lt;br /&gt;
===---- Simple Programs in PL/SQL===&lt;br /&gt;
&lt;br /&gt;
The simplest form of program has some declarations followed by an executable section consisting of one or more of the SQL statements with which we are familiar. The major nuance is that the form of the &amp;lt;tt&amp;gt;SELECT&amp;lt;/tt&amp;gt; statement is different from its SQL form. After the &amp;lt;tt&amp;gt;SELECT&amp;lt;/tt&amp;gt; clause, we ''must'' have an &amp;lt;tt&amp;gt;INTO&amp;lt;/tt&amp;gt; clause listing variables, one for each attribute in the &amp;lt;tt&amp;gt;SELECT&amp;lt;/tt&amp;gt; clause, into which the components of the retrieved tuple must be placed.&lt;br /&gt;
&lt;br /&gt;
Notice we said &amp;quot;tuple&amp;quot; rather than &amp;quot;tuples&amp;quot;, since the &amp;lt;tt&amp;gt;SELECT&amp;lt;/tt&amp;gt; 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 &amp;quot;single-row select&amp;quot; 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:&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE T1(&lt;br /&gt;
     e INTEGER,&lt;br /&gt;
     f INTEGER&lt;br /&gt;
 );&lt;br /&gt;
 &lt;br /&gt;
 DELETE FROM T1;&lt;br /&gt;
 INSERT INTO T1 VALUES(1, 3);&lt;br /&gt;
 INSERT INTO T1 VALUES(2, 4);&lt;br /&gt;
 &lt;br /&gt;
 /* Above is plain SQL; below is the PL/SQL program. */&lt;br /&gt;
 &lt;br /&gt;
 DECLARE&lt;br /&gt;
     a NUMBER;&lt;br /&gt;
     b NUMBER;&lt;br /&gt;
 BEGIN&lt;br /&gt;
     SELECT e,f INTO a,b FROM T1 WHERE e&amp;amp;gt;1;&lt;br /&gt;
     INSERT INTO T1 VALUES(b,a);&lt;br /&gt;
 END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
Fortuitously, there is only one tuple of &amp;lt;tt&amp;gt;T1&amp;lt;/tt&amp;gt; that has first component greater than 1, namely (2,4). The &amp;lt;tt&amp;gt;INSERT&amp;lt;/tt&amp;gt; statement thus inserts (4,2) into &amp;lt;tt&amp;gt;T1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===---- Control Flow in PL/SQL===&lt;br /&gt;
&lt;br /&gt;
PL/SQL allows you to branch and create loops in a fairly familiar way.&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;tt&amp;gt;IF&amp;lt;/tt&amp;gt; statement looks like:&lt;br /&gt;
&lt;br /&gt;
 IF &amp;amp;lt;condition&amp;amp;gt; THEN &amp;amp;lt;statement_list&amp;amp;gt; ELSE &amp;amp;lt;statement_list&amp;amp;gt; END IF;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;ELSE&amp;lt;/tt&amp;gt; part is optional. If you want a multiway branch, use:&lt;br /&gt;
&lt;br /&gt;
 IF &amp;amp;lt;condition_1&amp;amp;gt; THEN ...&lt;br /&gt;
 ELSIF &amp;amp;lt;condition_2&amp;amp;gt; THEN ...&lt;br /&gt;
 ... ...&lt;br /&gt;
 ELSIF &amp;amp;lt;condition_n&amp;amp;gt; THEN ...&lt;br /&gt;
 ELSE ...&lt;br /&gt;
 END IF;&lt;br /&gt;
&lt;br /&gt;
The following is an example, slightly modified from the previous one, where now we only do the insertion if the second component is 1. If not, we first add 10 to each component and then insert:&lt;br /&gt;
&lt;br /&gt;
 DECLARE&lt;br /&gt;
     a NUMBER;&lt;br /&gt;
     b NUMBER;&lt;br /&gt;
 BEGIN&lt;br /&gt;
     SELECT e,f INTO a,b FROM T1 WHERE e&amp;amp;gt;1;&lt;br /&gt;
     IF b=1 THEN&lt;br /&gt;
         INSERT INTO T1 VALUES(b,a);&lt;br /&gt;
     ELSE&lt;br /&gt;
         INSERT INTO T1 VALUES(b+10,a+10);&lt;br /&gt;
     END IF;&lt;br /&gt;
 END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
Loops are created with the following:&lt;br /&gt;
&lt;br /&gt;
 LOOP&lt;br /&gt;
     &amp;amp;lt;loop_body&amp;amp;gt; /* A list of statements. */&lt;br /&gt;
 END LOOP;&lt;br /&gt;
&lt;br /&gt;
At least one of the statements in &amp;lt;tt&amp;gt;&amp;amp;lt;loop_body&amp;amp;gt;&amp;lt;/tt&amp;gt; should be an &amp;lt;tt&amp;gt;EXIT&amp;lt;/tt&amp;gt; statement of the form&lt;br /&gt;
&lt;br /&gt;
 EXIT WHEN &amp;amp;lt;condition&amp;amp;gt;;&lt;br /&gt;
&lt;br /&gt;
The loop breaks if &amp;lt;tt&amp;gt;&amp;amp;lt;condition&amp;amp;gt;&amp;lt;/tt&amp;gt; is true. For example, here is a way to insert each of the pairs (1, 1) through (100, 100) into &amp;lt;tt&amp;gt;T1&amp;lt;/tt&amp;gt; of the above two examples:&lt;br /&gt;
&lt;br /&gt;
 DECLARE&lt;br /&gt;
     i NUMBER := 1;&lt;br /&gt;
 BEGIN&lt;br /&gt;
     LOOP&lt;br /&gt;
         INSERT INTO T1 VALUES(i,i);&lt;br /&gt;
         i := i+1;&lt;br /&gt;
         EXIT WHEN i&amp;amp;gt;100;&lt;br /&gt;
     END LOOP;&lt;br /&gt;
 END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
Some other useful loop-forming statements are:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;EXIT&amp;lt;/tt&amp;gt; by itself is an unconditional loop break. Use it inside a conditional if you like.&lt;br /&gt;
* A &amp;lt;tt&amp;gt;WHILE&amp;lt;/tt&amp;gt; loop can be formed with     WHILE &amp;amp;lt;condition&amp;amp;gt; LOOP&lt;br /&gt;
         &amp;amp;lt;loop_body&amp;amp;gt;&lt;br /&gt;
     END LOOP;&lt;br /&gt;
* A simple &amp;lt;tt&amp;gt;FOR&amp;lt;/tt&amp;gt; loop can be formed with:     FOR &amp;amp;lt;var&amp;amp;gt; IN &amp;amp;lt;start&amp;amp;gt;..&amp;amp;lt;finish&amp;amp;gt; LOOP&lt;br /&gt;
         &amp;amp;lt;loop_body&amp;amp;gt;&lt;br /&gt;
     END LOOP;&amp;lt;tt&amp;gt;&amp;amp;lt;var&amp;amp;gt;&amp;lt;/tt&amp;gt;&amp;lt;tt&amp;gt;&amp;amp;lt;start&amp;amp;gt;&amp;lt;/tt&amp;gt;&amp;lt;tt&amp;gt;&amp;amp;lt;finish&amp;amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===---- Cursors===&lt;br /&gt;
&lt;br /&gt;
A ''cursor'' is a variable whose value is a tuple of some relation; typically that relation is not a stored relation but is the answer to some query. By fetching into the cursor each tuple of the relation, we can write a program that acts on each such tuple.&lt;br /&gt;
&lt;br /&gt;
The example below illustrates a cursor fetch loop. It uses our example relation &amp;lt;tt&amp;gt;T1(e,f)&amp;lt;/tt&amp;gt; whose tuples are pairs of integers. The program looks at each tuple and, if the first component is less than the second, inserts the reverse tuple into &amp;lt;tt&amp;gt;T1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
  1) DECLARE&lt;br /&gt;
         /* Output variables to hold the result of the query: */&lt;br /&gt;
  2)     a T1.e%TYPE;&lt;br /&gt;
  3)     b T1.f%TYPE;&lt;br /&gt;
         /* Cursor declaration: */&lt;br /&gt;
  4)     CURSOR T1Cursor IS&lt;br /&gt;
  5)         SELECT e, f&lt;br /&gt;
  6)         FROM T1&lt;br /&gt;
  7)         WHERE e &amp;amp;lt; f;&lt;br /&gt;
  8) BEGIN&lt;br /&gt;
  9)     OPEN T1Cursor;&lt;br /&gt;
 10)     LOOP&lt;br /&gt;
             /* Retrieve each row of the result of the above query&lt;br /&gt;
                into PL/SQL variables: */&lt;br /&gt;
 11)         FETCH T1Cursor INTO a, b;&lt;br /&gt;
             /* If there are no more rows to fetch, exit the loop: */&lt;br /&gt;
 12)         EXIT WHEN T1Cursor%NOTFOUND;&lt;br /&gt;
             /* Insert the reverse tuple: */&lt;br /&gt;
 13)         INSERT INTO T1 VALUES(b, a);&lt;br /&gt;
 14)     END LOOP;&lt;br /&gt;
         /* Free cursor used by the query. */&lt;br /&gt;
 15)     CLOSE T1Cursor;&lt;br /&gt;
 16) END;&lt;br /&gt;
 17) .&lt;br /&gt;
 18) run;&lt;br /&gt;
&lt;br /&gt;
Here are explanations for the various lines of this program:&lt;br /&gt;
&lt;br /&gt;
* Line (1) introduces the declaration section.&lt;br /&gt;
* Lines (2) and (3) declare variables &amp;lt;tt&amp;gt;a&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;b&amp;lt;/tt&amp;gt; to have types equal to the types of attributes &amp;lt;tt&amp;gt;e&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;f&amp;lt;/tt&amp;gt; of the relation &amp;lt;tt&amp;gt;T1&amp;lt;/tt&amp;gt;. Although we know these types are &amp;lt;tt&amp;gt;INTEGER&amp;lt;/tt&amp;gt;, 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 &amp;lt;tt&amp;gt;NUMBER&amp;lt;/tt&amp;gt;).&lt;br /&gt;
* Lines (4) through (7) define the cursor &amp;lt;tt&amp;gt;T1Cursor&amp;lt;/tt&amp;gt;. It ranges over a relation defined by the &amp;lt;tt&amp;gt;SELECT&amp;lt;/tt&amp;gt;-&amp;lt;tt&amp;gt;FROM&amp;lt;/tt&amp;gt;-&amp;lt;tt&amp;gt;WHERE&amp;lt;/tt&amp;gt; query. That query selects those tuples of &amp;lt;tt&amp;gt;T1&amp;lt;/tt&amp;gt; whose first component is less than the second component.&lt;br /&gt;
* Line (8) begins the executable section of the program.&lt;br /&gt;
* Line (9) opens the cursor, an essential step.&lt;br /&gt;
* Lines (10) through (14) are a PL/SQL loop. Notice that such a loop is bracketed by &amp;lt;tt&amp;gt;LOOP&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;END LOOP&amp;lt;/tt&amp;gt;. Within the loop we find:&lt;br /&gt;
** On Line (11), a fetch through the cursor into the local variables. In general, the &amp;lt;tt&amp;gt;FETCH&amp;lt;/tt&amp;gt; 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.&lt;br /&gt;
** On Line (12), a test for the loop-breaking condition. Its meaning should be clear: &amp;lt;tt&amp;gt;%NOTFOUND&amp;lt;/tt&amp;gt; after the name of a cursor is true exactly when a fetch through that cursor has failed to find any more tuples.&lt;br /&gt;
** On Line (13), a SQL &amp;lt;tt&amp;gt;INSERT&amp;lt;/tt&amp;gt; statement that inserts the reverse tuple into &amp;lt;tt&amp;gt;T1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
* Line (15) closes the cursor.&lt;br /&gt;
* Line (16) ends the PL/SQL program.&lt;br /&gt;
* Lines (17) and (18) cause the program to execute.&lt;br /&gt;
&lt;br /&gt;
===---- Procedures===&lt;br /&gt;
&lt;br /&gt;
PL/SQL procedures behave very much like procedures in other programming language. Here is an example of a PL/SQL procedure &amp;lt;tt&amp;gt;addtuple1&amp;lt;/tt&amp;gt; that, given an integer &amp;lt;tt&amp;gt;i&amp;lt;/tt&amp;gt;, inserts the tuple &amp;lt;tt&amp;gt;(i, 'xxx')&amp;lt;/tt&amp;gt; into the following example relation:&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE T2 (&lt;br /&gt;
     a INTEGER,&lt;br /&gt;
     b CHAR(10)&lt;br /&gt;
 );&lt;br /&gt;
 &lt;br /&gt;
 CREATE PROCEDURE addtuple1(i IN NUMBER) AS&lt;br /&gt;
 BEGIN&lt;br /&gt;
     INSERT INTO T2 VALUES(i, 'xxx');&lt;br /&gt;
 END addtuple1;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
A procedure is introduced by the keywords &amp;lt;tt&amp;gt;CREATE PROCEDURE&amp;lt;/tt&amp;gt; followed by the procedure name and its parameters. An option is to follow &amp;lt;tt&amp;gt;CREATE&amp;lt;/tt&amp;gt; by &amp;lt;tt&amp;gt;OR REPLACE&amp;lt;/tt&amp;gt;. The advantage of doing so is that should you have already made the definition, you will not get an error. On the other hand, should the previous definition be a different procedure of the same name, you will not be warned, and the old procedure will be lost.&lt;br /&gt;
&lt;br /&gt;
There can be any number of parameters, each followed by a ''mode'' and a type. The possible modes are &amp;lt;tt&amp;gt;IN&amp;lt;/tt&amp;gt; (read-only), &amp;lt;tt&amp;gt;OUT&amp;lt;/tt&amp;gt; (write-only), and &amp;lt;tt&amp;gt;INOUT&amp;lt;/tt&amp;gt; (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, &amp;lt;tt&amp;gt;CHAR(10)&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;VARCHAR(20)&amp;lt;/tt&amp;gt; are illegal; &amp;lt;tt&amp;gt;CHAR&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;VARCHAR&amp;lt;/tt&amp;gt; should be used instead. The actual length of a parameter depends on the corresponding argument that is passed in when the procedure is invoked.&lt;br /&gt;
&lt;br /&gt;
Following the arguments is the keyword &amp;lt;tt&amp;gt;AS&amp;lt;/tt&amp;gt; (&amp;lt;tt&amp;gt;IS&amp;lt;/tt&amp;gt; is a synonym). Then comes the body, which is essentially a PL/SQL block. We have repeated the name of the procedure after the &amp;lt;tt&amp;gt;END&amp;lt;/tt&amp;gt;, but this is optional. However, the &amp;lt;tt&amp;gt;DECLARE&amp;lt;/tt&amp;gt; section should ''not'' start with the keyword &amp;lt;tt&amp;gt;DECLARE&amp;lt;/tt&amp;gt;. Rather, following &amp;lt;tt&amp;gt;AS&amp;lt;/tt&amp;gt; we have:&lt;br /&gt;
&lt;br /&gt;
 ... AS&lt;br /&gt;
 &amp;amp;lt;local_var_declarations&amp;amp;gt;&lt;br /&gt;
 BEGIN&lt;br /&gt;
     &amp;amp;lt;procedure_body&amp;amp;gt;&lt;br /&gt;
 END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;run&amp;lt;/tt&amp;gt; at the end runs the statement that ''creates'' the procedure; it does not execute the procedure. To execute the procedure, use another PL/SQL statement, in which the procedure is invoked as an executable statement. For example:&lt;br /&gt;
&lt;br /&gt;
 BEGIN addtuple1(99); END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
The following procedure also inserts a tuple into &amp;lt;tt&amp;gt;T2&amp;lt;/tt&amp;gt;, but it takes both components as arguments:&lt;br /&gt;
&lt;br /&gt;
 CREATE PROCEDURE addtuple2(&lt;br /&gt;
     x T2.a%TYPE,&lt;br /&gt;
     y T2.b%TYPE)&lt;br /&gt;
 AS&lt;br /&gt;
 BEGIN&lt;br /&gt;
     INSERT INTO T2(a, b)&lt;br /&gt;
     VALUES(x, y);&lt;br /&gt;
 END addtuple2;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
Now, to add a tuple &amp;lt;tt&amp;gt;(10, 'abc')&amp;lt;/tt&amp;gt; to &amp;lt;tt&amp;gt;T2&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 BEGIN&lt;br /&gt;
     addtuple2(10, 'abc');&lt;br /&gt;
 END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
The following illustrates the use of an &amp;lt;tt&amp;gt;OUT&amp;lt;/tt&amp;gt; parameter:&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE T3 (&lt;br /&gt;
     a INTEGER,&lt;br /&gt;
     b INTEGER&lt;br /&gt;
 );&lt;br /&gt;
 &lt;br /&gt;
 CREATE PROCEDURE addtuple3(a NUMBER, b OUT NUMBER)&lt;br /&gt;
 AS&lt;br /&gt;
 BEGIN&lt;br /&gt;
     b := 4;&lt;br /&gt;
     INSERT INTO T3 VALUES(a, b);&lt;br /&gt;
 END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
 &lt;br /&gt;
 DECLARE&lt;br /&gt;
     v NUMBER;&lt;br /&gt;
 BEGIN&lt;br /&gt;
     addtuple3(10, v);&lt;br /&gt;
 END;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
Note that assigning values to parameters declared as &amp;lt;tt&amp;gt;OUT&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;INOUT&amp;lt;/tt&amp;gt; causes the corresponding input arguments to be written. Because of this, the input argument for an &amp;lt;tt&amp;gt;OUT&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;INOUT&amp;lt;/tt&amp;gt; parameter should be something with an &amp;quot;lvalue&amp;quot;, such as a variable like &amp;lt;tt&amp;gt;v&amp;lt;/tt&amp;gt; in the example above. A constant or a literal argument should not be passed in for an &amp;lt;tt&amp;gt;OUT&amp;lt;/tt&amp;gt;/&amp;lt;tt&amp;gt;INOUT&amp;lt;/tt&amp;gt; parameter.&lt;br /&gt;
&lt;br /&gt;
We can also write functions instead of procedures. In a function declaration, we follow the parameter list by &amp;lt;tt&amp;gt;RETURN&amp;lt;/tt&amp;gt; and the type of the return value:&lt;br /&gt;
&lt;br /&gt;
 CREATE FUNCTION &amp;amp;lt;func_name&amp;amp;gt;(&amp;amp;lt;param_list&amp;amp;gt;) RETURN &amp;amp;lt;return_type&amp;amp;gt; AS ...&lt;br /&gt;
&lt;br /&gt;
In the body of the function definition, &amp;quot;&amp;lt;tt&amp;gt;RETURN &amp;amp;lt;expression&amp;amp;gt;&amp;lt;/tt&amp;gt;;&amp;quot; exits from the function and returns the value of &amp;lt;tt&amp;gt;&amp;amp;lt;expression&amp;amp;gt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To find out what procedures and functions you have created, use the following SQL query:&lt;br /&gt;
&lt;br /&gt;
 select object_type, object_name&lt;br /&gt;
 from user_objects&lt;br /&gt;
 where object_type = 'PROCEDURE'&lt;br /&gt;
    or object_type = 'FUNCTION';&lt;br /&gt;
&lt;br /&gt;
To drop a stored procedure/function:&lt;br /&gt;
&lt;br /&gt;
 drop procedure &amp;amp;lt;procedure_name&amp;amp;gt;;&lt;br /&gt;
 drop function &amp;amp;lt;function_name&amp;amp;gt;;&lt;br /&gt;
&lt;br /&gt;
===---- Triggers===&lt;br /&gt;
&lt;br /&gt;
Triggers are a special PL/SQL construct similar to procedures. However, a procedure is executed explicitly from another block via a procedure call, while a trigger is executed implicitly whenever the triggering event happens. The triggering event is either a &amp;lt;tt&amp;gt;INSERT&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;DELETE&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;UPDATE&amp;lt;/tt&amp;gt; command. The timing can be either &amp;lt;tt&amp;gt;BEFORE&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;AFTER&amp;lt;/tt&amp;gt;. The trigger can be either row-level or statement-level, where the former fires once for each row affected by the triggering statement and the latter fires once for the whole statement.&lt;br /&gt;
&lt;br /&gt;
Below is the syntax for creating a trigger in Oracle (this syntax has been simplified; for the complete version try &amp;lt;tt&amp;gt;HELP CREATE TRIGGER&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;sqlplus&amp;lt;/tt&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
 CREATE [OR REPLACE] TRIGGER &amp;amp;lt;trigger_name&amp;amp;gt;&lt;br /&gt;
     {BEFORE|AFTER} {INSERT|DELETE|UPDATE} ON &amp;amp;lt;table_name&amp;amp;gt;&lt;br /&gt;
     [FOR EACH ROW [WHEN (&amp;amp;lt;trigger_condition&amp;amp;gt;)]]&lt;br /&gt;
     &amp;amp;lt;trigger_body&amp;amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some important points to note:&lt;br /&gt;
&lt;br /&gt;
* Only &amp;lt;tt&amp;gt;BEFORE&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;AFTER&amp;lt;/tt&amp;gt; options are supported; &amp;lt;tt&amp;gt;INSTEAD OF&amp;lt;/tt&amp;gt; is not.&lt;br /&gt;
&lt;br /&gt;
* You may specify up to three triggering events using the keyword &amp;lt;tt&amp;gt;OR&amp;lt;/tt&amp;gt;. Furthermore, &amp;lt;tt&amp;gt;UPDATE&amp;lt;/tt&amp;gt; can be optionally followed by the keyword &amp;lt;tt&amp;gt;OF&amp;lt;/tt&amp;gt; and a list of attribute(s) in &amp;lt;tt&amp;gt;&amp;amp;lt;table_name&amp;amp;gt;&amp;lt;/tt&amp;gt;. If present, the &amp;lt;tt&amp;gt;OF&amp;lt;/tt&amp;gt; clause defines the event to be only an update of the attribute(s) listed after &amp;lt;tt&amp;gt;OF&amp;lt;/tt&amp;gt;. Here are some examples:     ... INSERT ON R ...&lt;br /&gt;
     ... INSERT OR DELETE OR UPDATE ON R ...&lt;br /&gt;
     ... UPDATE OF A, B OR INSERT ON R ...&lt;br /&gt;
&lt;br /&gt;
* If &amp;lt;tt&amp;gt;FOR EACH ROW&amp;lt;/tt&amp;gt; option is specified, the trigger is row-level; otherwise, the trigger is statement-level.&lt;br /&gt;
&lt;br /&gt;
* For a row-level trigger, a trigger restriction can be specified in the &amp;lt;tt&amp;gt;WHEN&amp;lt;/tt&amp;gt; clause, enclosed by parentheses. The trigger restriction is a SQL condition that must be satisfied in order for Oracle to fire the trigger. This condition cannot contain subqueries. Without the &amp;lt;tt&amp;gt;WHEN&amp;lt;/tt&amp;gt; clause, a trigger is fired by every triggering event.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;&amp;amp;lt;trigger_body&amp;amp;gt;&amp;lt;/tt&amp;gt; is a PL/SQL block, rather than sequence of SQL statements. Oracle has placed certain restrictions on what you can do in &amp;lt;tt&amp;gt;&amp;amp;lt;trigger_body&amp;amp;gt;&amp;lt;/tt&amp;gt;, in order to avoid situations where one trigger performs an action that triggers a second trigger, which then triggers a third, and so on, which could potentially create an infinite loop. The restrictions on &amp;lt;tt&amp;gt;&amp;amp;lt;trigger_body&amp;amp;gt;&amp;lt;/tt&amp;gt; include:&lt;br /&gt;
** You cannot modify the same relation whose modification is the event triggering the trigger.&lt;br /&gt;
** You cannot modify a relation connected to the triggering relation by another constraint such as a foreign-key constraint.&lt;br /&gt;
&lt;br /&gt;
We illustrate Oracle's syntax for creating a trigger through an example based on the following two tables:&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE T4 (a INTEGER, b CHAR(10));&lt;br /&gt;
 CREATE TABLE T5 (c CHAR(10), d INTEGER);&lt;br /&gt;
&lt;br /&gt;
We create a trigger that may insert a tuple into &amp;lt;tt&amp;gt;T5&amp;lt;/tt&amp;gt; when a tuple is inserted into &amp;lt;tt&amp;gt;T4&amp;lt;/tt&amp;gt;. Specifically, the trigger checks whether the new tuple has a first component 10 or less, and if so inserts the reverse tuple into &amp;lt;tt&amp;gt;T5&amp;lt;/tt&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 CREATE TRIGGER trig1&lt;br /&gt;
     AFTER INSERT ON T4&lt;br /&gt;
     FOR EACH ROW&lt;br /&gt;
     WHEN (NEW.a &amp;amp;lt;= 10)&lt;br /&gt;
     BEGIN&lt;br /&gt;
         INSERT INTO T5 VALUES(:NEW.b, :NEW.a);&lt;br /&gt;
     END trig1;&lt;br /&gt;
 .&lt;br /&gt;
 run;&lt;br /&gt;
&lt;br /&gt;
The special variables &amp;lt;tt&amp;gt;NEW&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;OLD&amp;lt;/tt&amp;gt; are available to refer to new and old tuples respectively. '''Note:''' In the trigger body, &amp;lt;tt&amp;gt;NEW&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;OLD&amp;lt;/tt&amp;gt; must be preceded by a colon (&amp;quot;&amp;lt;tt&amp;gt;:&amp;lt;/tt&amp;gt;&amp;quot;), but in the &amp;lt;tt&amp;gt;WHEN&amp;lt;/tt&amp;gt; clause, they do not have a preceding colon!&lt;br /&gt;
&lt;br /&gt;
Again, notice that we end the &amp;lt;tt&amp;gt;CREATE TRIGGER&amp;lt;/tt&amp;gt; statement with a dot and &amp;lt;tt&amp;gt;run&amp;lt;/tt&amp;gt;, as for all PL/SQL statements in general. Running the &amp;lt;tt&amp;gt;CREATE TRIGGER&amp;lt;/tt&amp;gt; statement only creates the trigger; it does not execute the trigger. Only a triggering event, such as an insertion into &amp;lt;tt&amp;gt;T4&amp;lt;/tt&amp;gt; in this example, causes the trigger to execute.&lt;br /&gt;
&lt;br /&gt;
To view information about your triggers, use the following:&lt;br /&gt;
&lt;br /&gt;
 select trigger_name from user_triggers;&lt;br /&gt;
 &lt;br /&gt;
 select trigger_type, table_name, triggering_event&lt;br /&gt;
 from user_triggers&lt;br /&gt;
 where trigger_name = '&amp;amp;lt;trigger_name&amp;amp;gt;';&lt;br /&gt;
&lt;br /&gt;
To drop a trigger:&lt;br /&gt;
&lt;br /&gt;
 drop trigger &amp;amp;lt;trigger_name&amp;amp;gt;;&lt;br /&gt;
&lt;br /&gt;
To disable or enable a trigger:&lt;br /&gt;
&lt;br /&gt;
 alter trigger &amp;amp;lt;trigger_name&amp;amp;gt; {disable|enable};&lt;br /&gt;
&lt;br /&gt;
===---- Discovering Errors===&lt;br /&gt;
&lt;br /&gt;
PL/SQL does not always tell you about compilation errors. Instead, it gives you a cryptic message such as &amp;quot;procedure created with compilation errors&amp;quot;. If you don't see what is wrong immediately, try issuing the command&lt;br /&gt;
&lt;br /&gt;
 show errors procedure &amp;amp;lt;procedure_name&amp;amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Similarly, you can get the errors associated with a created trigger by&lt;br /&gt;
&lt;br /&gt;
 show errors trigger &amp;amp;lt;trigger_name&amp;amp;gt;;&lt;br /&gt;
&lt;br /&gt;
Furthermore, &amp;quot;&amp;lt;tt&amp;gt;SHO ERR&amp;lt;/tt&amp;gt;&amp;quot; is an abbreviation for &amp;quot;&amp;lt;tt&amp;gt;SHOW ERRORS&amp;lt;/tt&amp;gt;&amp;quot;, and you can omit &amp;quot;&amp;lt;tt&amp;gt;PROCEDURE ...&amp;lt;/tt&amp;gt;&amp;quot; or &amp;quot;&amp;lt;tt&amp;gt;TRIGGER ...&amp;lt;/tt&amp;gt;&amp;quot; if you just want to see the most recent compilation error.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&amp;lt;font size=&amp;quot;-2&amp;quot;&amp;gt;This document is written originally for Prof. Jeff Ullman's CS145 class in Autumn, 1997; revised by Jun Yang for Prof. Jennifer Widom's CS145 class in Spring, 1998.&amp;lt;/font&amp;gt;&lt;/div&gt;</summary>
		<author><name>MassBot1</name></author>
	</entry>
</feed>