CSE 781 Data Base Management Systems, Summer 09 Lecture 3

CSE 781 Data Base Management Systems, Summer 09 Lecture 3

<p>CSE 781 Data Base Management Systems, Summer ’09 Lecture 3 More PL/SQL</p><p>PROCEDURES</p><p>Procedures are programming units that help to accomplish tasks. They make the work lot easier as they are reusable, i.e., they can be used in other programming units as well. Procedures are not full blown applications; but, they do help automate processes and can be part of an application. Many RDBMSs allow procedures to be stored in the database itself along with other database objects such as tables and views. </p><p>Procedures are important because they can be used to ensure that the database remains in a consistent state. They can be used to implement constraints that cannot be easily implemented other ways. They can also be used to ensure data integrity by performing calculations and updating values based on triggering events, facilitate data retrieval, and facilitate repetitive tasks.</p><p>The different types of procedures supported in Oracle 10g are:  unnamed stored procedures,  named stored procedures,  functions,  table level triggers, and  system event triggers.</p><p>Structure of a procedure consists of DECLARE and BEGIN sections terminated by an END statement. These blocks of code can be named or unnamed. Unnamed blocks are also referred as anonymous blocks. The basic structure is the same whether the blocks are named or anonymous. </p><p>I. ANONYMOUS/UNNAMED PROCEDURES </p><p>Examine the block’s structure below: Put your variables here. DECLARE Think of variables as memory work areas that temporarily hold data. BEGIN</p><p>Put your executable PL/SQL statements here. Each statement ends with a semi- colon. END;</p><p>Example: Let us write a simple procedure to display a name on the screen.</p><p>Rajika Tandon Page 1 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>Other important things to know which you might need in your procedures</p><p>1. DBMS_OUTPUT.PUTLINE()</p><p>Oracle provides a named stored procedure that can be used to display a message to the output device. This stored procedure is named PUT_LINE and it is located in the DBMS_OUTPUT package. A package is a schema object that groups logically related PL/SQL types, items, and subprograms. A Package, in a way, stores collection of subprograms (procedures, functions, etc.). </p><p>Syntax:</p><p>DBMS_OUTPUT.PUT_LINE(parameter to be displayed);</p><p> package Dot procedure parameter list name operator name</p><p>This PL/SQL statement will call the PUT_LINE procedure in the DBMS_OUTPUT package (which is located in the SYS schema) and pass the parameter (whatever you want to display) inside the parenthesis. A literal is a character string that must have single quotes (‘) at the beginning and end of the string. You may display multiple variables and/or literals by concatenating them together. Two OR bar symbols (||) are used as the concatenate symbol (some refer to the OR bar symbol as a pipe). To simply display my name the procedure call would look like:</p><p>DBMS_OUTPUT.PUT_LINE(‘Rajika’);</p><p>To display my name and the value stored in a variable named suidVar, the procedure call would look like:</p><p>DBMS_OUTPUT.PUT_LINE(‘Rajika’s SUID is‘ || suid || ‘, and she is a graduate student.’); </p><p>A simple name display unnamed procedure is as follows: </p><p>BEGIN DBMS_OUTPUT.PUT_LINE('Rajika’); END;</p><p>To execute this procedure give a forward slash (/) but you’ll be surprised that even though the procedure will be successfully created, you won’t be able to view the output !</p><p>Rajika Tandon Page 2 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>For that you need to give the following command before invoking the procedure:</p><p>SET SERVEROUTPUT ON</p><p>Notice that we did not need the DECLARE section for this simple procedure since there was nothing required to be declared. </p><p>A variable is a named memory location that contains a value that can change. In PL/SQL you declare all variables in the DECLARE section. the format is </p><p> variableName type := value; Notice: this is a colon equal sign ( := )</p><p> where: variableName = the name you have assigned to the variable type = the data type of the variable value = initialization value</p><p>Rajika Tandon Page 3 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>The following is another example of a more complex unnamed procedure block.</p><p>/* Program: CSE781.sql Author: Rajika Tandon Date: May 10, 2009 Comments: This is an example of an unnamed procedure block that prints my name and the current system date. */ SET SERVEROUTPUT ON</p><p>DECLARE</p><p> curDateVar DATE; /* defines a variable with the DATE datatype */ nameVar VARCHAR(15) := ‘RAJIKA TANDON’;</p><p>BEGIN</p><p> curDateVar := SYSDATE;</p><p>DBMS_OUTPUT.PUT_LINE('Hi I am ‘ || nameVar); DBMS_OUTPUT.PUT_LINE(‘How may I help you today (‘ || curDateVar || ‘) ? ’);</p><p>END; Notice that two “or” bars or pipes are used to concatenate character strings.</p><p>2. VARIABLES AND ANCHOR DATA TYPES</p><p>Consider the following table: CREATE TABLE Student ( studID INT PRIMARY KEY, studName VARCHAR(20) NOT NULL, studGPA DECIMAL(3,2) NOT NULL );</p><p>Suppose you want to display the name, id and GPA of a student with studentID = 30. You might need to declare variable inside the declare section for some computation inside a procedure.</p><p>In order to declare a variable, we must tell the procedure what type of data we want to store. In the case of PL/SQL procedures, we want to make them as flexible as possible. If, for example, the data type of a table attribute is changed, it would be difficult to have to change all of the stored procedures that use that attribute. Therefore, if we were actually retrieving the name from a table, we would want a way to ensure that if the data type in the table was changed, the stored</p><p>Rajika Tandon Page 4 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3 procedure would be changed automatically. For e.g. in the table Student, studName is declared as VARCHAR(20), then it was changed to VARCHAR2(25). This can be accomplished using an anchor data type.</p><p>An anchor data type tells the procedure to use the data type of the attribute defined in a database table, i.e. you can tell the procedure to use the same data type that was used in the CREATE TABLE. This is done as follows:</p><p> nameVar Student.studName%TYPE;</p><p>3. SELECT Statements in PL/SQL</p><p>INTO Clause The INTO clause is mandatory and occurs between the SELECT and FROM clauses. It is used to specify the names of variables that hold the values that SQL returns from the SELECT clause. You must specify one variable for each item selected, and the order of the variables must correspond with the items selected.</p><p>Use the INTO clause to populate either PL/SQL variables or host variables (used for communication between a host language and a PL/SQL block).</p><p>Queries Must Return One and Only One Row SELECT statements within a PL/SQL block fall into the ANSI classification of embedded SQL, for which the following rule applies: queries must return one and only one row. A query that returns more than one row or no row generates an error. PL/SQL manages these errors by raising standard exceptions, which you can trap in the exception section of the block with the NO_DATA_FOUND and TOO_MANY_ROWS exceptions (exception handling is not covered in this class due to time time constraint). Code SELECT statements in such a way that they return a single row.</p><p>E.g.</p><p>To fetch the record of a student with id as 30, we’ll write the following query:</p><p>SELECT studID, studName, studGPA FROM Student where studID = 30;</p><p>If we have declared variables to hold the name attributes in the procedure, we could declare those variables using the anchor data type and then populate the variables using the appropriate SELECT. It might look like this: DECLARE nameVar Student.studName%TYPE; /* anchor data type */ </p><p>Rajika Tandon Page 5 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p> gpaVar Student.studGPA%TYPE;</p><p>BEGIN /* Select the student record from the table */</p><p>SELECT studName, studGPA INTO nameVar, gpaVar FROM Student WHERE studID = 30;</p><p>DBMS_OUTPUT.PUT_LINE(‘Student ID = 30’); DBMS_OUTPUT.PUT_LINE(‘Student Name = ‘ || nameVar); DBMS_OUTPUT.PUT_LINE(‘Student GPA = ‘ || gpaVar); END; /</p><p>Rajika Tandon Page 6 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>3. SUBSTITUTION VARIABLES</p><p>The previous example has a hard-coded value for the student ID. What if you want to do this for any desired student ? To make this procedure flexible enough to allow any student’s record to be displayed, we’ll make use of a substitution variable. A substitution variable is Oracle’s way of allowing the procedure to prompt the user for a variable’s value at run time. It is preceeded by an ‘&’ (ampersand) symbol.</p><p>So the previous example can be made more flexible using such a substitution variable (naming convention I use is <variable-name>SubVar) as shown in the following code and screenshots: set serveroutput on</p><p>DECLARE nameVar Student.studName%TYPE; /* anchor data type */ gpaVar Student.studGPA%TYPE; idVar Student.studID%TYPE := &idSubVar; BEGIN /* Select the student record from the table */</p><p>SELECT studName, studGPA INTO nameVar, gpaVar FROM Student</p><p>Rajika Tandon Page 7 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>WHERE studID = idVar;</p><p>DBMS_OUTPUT.PUT_LINE('Student ID = ' || idVar); DBMS_OUTPUT.PUT_LINE('Student Name = ' || nameVar); DBMS_OUTPUT.PUT_LINE('Student GPA = ' || gpaVar); END; /</p><p>When you’ll execute the above anonymous procedure, you’ll get the following screen, asking you the value of the substitution variable idSubVar. Then enter the desired value for idSubVar and click on continue.</p><p>Now you’ll get the following screen:</p><p>II. STORED PROCEDURES </p><p>Rajika Tandon Page 8 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>By creating stored procedures, we can store the program unit in a convenient location, the database, and allow access to any other user that we want. Also, stored procedures allow for input parameters as well as output parameters. That is, you can pass a value to the procedure to use when it executes and/or you can return a value to the calling procedure.</p><p>You’ll notice that the syntax of a stored procedure is very much similar to the syntax you used to create a function as discussed in the previous lecture.</p><p>Syntax: Procedure Name CREATE OR REPLACE PROCEDURE ProcedureName </p><p>( variable IN/OUT dataType defaultValue) Define all IN/OUT parameters IS Declare all variables</p><p>BEGIN Block of statements END;</p><p>The command to execute a stored procedure from SQL*Plus or other editor:</p><p>EXEC ProcedureName (parameter list);</p><p>E.g. I’ll create a named/stored procedure which takes the student id as input variable, and displays the record of that student, as well as tell us whether the student is eligible for scholarship or not (gpa > 3.75). </p><p>Note that it is my coding convention to attach a suffix in the input variable name of the type of the mode it is declared. For e.g. if a variable say studentID is given as parameter to a function or a procedure, i.e. studID IN INT, I prefer to write it as: studIDIN IN INT, so that when using this variable later in the code or re-checking my code, I may quickly understand what kind of variable studentID is! It is a good practice to suffix a variable or name by its mode/type.)</p><p> studIdIN is the Input parameter CREATE OR REPLACE PROCEDURE ScholarshipProc IN: indicates input parameter Rajika Tandon Page 9 OUT: indicates output parameter CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>(studIDIN IN INT)</p><p>IS Parameter type</p><p> nameVar Student.studName%TYPE; /* anchor data type */ gpaVar Student.studGPA%TYPE; </p><p>BEGIN /* Select the student record from the table */</p><p>SELECT studName, studGPA INTO nameVar, gpaVar FROM Student WHERE studID = studIDIN;</p><p>DBMS_OUTPUT.PUT_LINE('Student ID = ' || studIDIN); DBMS_OUTPUT.PUT_LINE('Student Name = ' || nameVar); DBMS_OUTPUT.PUT_LINE('Student GPA = ' || gpaVar);</p><p>IF gpaVar > 3.75 THEN DBMS_OUTPUT.PUT_LINE('Student is eligible for Scholarship'); ELSE DBMS_OUTPUT.PUT_LINE('Sorry. The student is ineligible for Scholarship'); END IF; END; /</p><p>The command to execute this procedure is: </p><p>EXEC ScholarshipProc (30);</p><p>Rajika Tandon Page 10 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>Now, we can name our stored procedures and store them conveniently in the database. They can be easily accessed by other database users and procedures. Stored procedures can execute other stored procedures passing and returning parameters which further adds to reusability. OUT mode comes pretty useful in such scenarios (not discussed in this document).</p><p>Rajika Tandon Page 11 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3 CURSORS</p><p>We are now in a position to write program units (procedures) that can solve complex problems, but we are limited to retrieve values in just a particular row using SELECT.. INTO. What if we want to retrieve multiple rows and perform some operations on it ? </p><p>We know that the data required for the procedures is stored in the database tables. When we use SQL SELECT command for selecting certain/all rows in a table, the data values are returned into a work area (database buffer cache) upon execution of this statement, and Oracle creates a pointer to the area which is called as a cursor. </p><p>There are implicit and explicit cursors. An implicit cursor is automatically established by Oracle every time an SQL statement is executed. The user is unaware of this cursor and has no way to control the process or the data using this cursor. If, however, you would like to have control and access each row individually, you can create an explicit cursor. Think of an explicit cursor as a pointer to the database buffer cache that has a name you know. Since you know the name that contains the address, you can now use the name to go to the address. </p><p>To implement a cursor, we must do the following: </p><p> declare the cursor in the DECLARE section,  open the cursor in the BEGIN (code) section,  fetch a row and continue until there are no more rows left in the cursor,  finally, close the cursor. Declare a cursors which includes the SELECT required to retrieve the data DECLARE CURSOR studCur IS SELECT * FROM Student; Declare a variable to hold the individual studRec Student%ROWTYPE; row Fetched /* or you can also declare: studRec studCur%ROWTYPE; but be careful to declare the cursor before doing so */</p><p>BEGIN Open the cursor OPEN studCur; LOOP Fetch (read) a single row from the FETCH studCur INTO studRec; cursor EXIT WHEN studCur%NOTFOUND; EXIT when there are no more rows /* display a record fetched */</p><p>DBMS_OUTPUT.PUT_LINE('Student ID = ' || studRec.studID); Rajika Tandon Page 12 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>DBMS_OUTPUT.PUT_LINE('Student Name = ' || studRec.studName); DBMS_OUTPUT.PUT_LINE('Student GPA = ' || studRec.studGPA); DBMS_OUTPUT.PUT_LINE('***************************************'); END LOOP; CLOSE studCUR; Close the cursor when processing is END; completed /</p><p>Rajika Tandon Page 13 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>Another Example: To display the records of only those students whose GPA is > gpaLimit (say 3.0 as given from the SQL environment to this procedure). I also want to display the no. of students with low GPA.</p><p>Right now the following data is present in the Student table:</p><p>Rajika Tandon Page 14 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>CREATE OR REPLACE PROCEDURE ScholarshipCurProc ( gpaLimitIN IN DECIMAL) IS CURSOR studCur IS SELECT * FROM Student;</p><p> studRec studCur%ROWTYPE; /* a variable to hold the individual row fetched */ lowGPAVar NUMBER := 0; /* initial value set to 0 */ BEGIN OPEN studCur; LOOP FETCH studCur INTO studRec; EXIT WHEN studCur%NOTFOUND;</p><p>IF studRec.studGPA > gpaLimitIN THEN DBMS_OUTPUT.PUT_LINE('Student ID = ' || studRec.studID); DBMS_OUTPUT.PUT_LINE('Student Name = ' || studRec.studName); DBMS_OUTPUT.PUT_LINE('Student GPA = ' || studRec.studGPA); DBMS_OUTPUT.PUT_LINE('***************************************'); ELSE lowGPAVar := lowGPAVar + 1; END IF; END LOOP; CLOSE studCUR;</p><p>DBMS_OUTPUT.PUT_LINE('No. of students with low GPA= ' || lowGPAVar);</p><p>END; /</p><p>EXEC ScholarshipCurProc (3.0);</p><p>Rajika Tandon Page 15 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>Just to show you how the above procedure executed:</p><p>Rajika Tandon Page 16 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>Yet Another Example: To display the records of only those students whose GPA is < 3.0 but specifying this condition within the cursor definition itself. (Efficient example than the previous case)</p><p>Note: Procedures and functions that take no parameters are written without parentheses.</p><p>CREATE OR REPLACE PROCEDURE SshipCurConditionProc /* I am not giving any parameter as I am hardcoding gpa < 3 in the code */ IS CURSOR studCur IS SELECT * FROM Student WHERE studGPA < 3.0;</p><p> studRec studCur%ROWTYPE; /* a variable to hold the individual row fetched */ BEGIN OPEN studCur; LOOP FETCH studCur INTO studRec; EXIT WHEN studCur%NOTFOUND;</p><p>/* display a record fetched */ DBMS_OUTPUT.PUT_LINE('Student ID = ' || studRec.studID); DBMS_OUTPUT.PUT_LINE('Student Name = ' || studRec.studName); DBMS_OUTPUT.PUT_LINE('Student GPA = ' || studRec.studGPA); DBMS_OUTPUT.PUT_LINE('***************************************'); END LOOP; CLOSE studCUR; END; / exec SshipCurConditionProc(); or exec SshipCurConditionProc;</p><p>Rajika Tandon Page 17 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>Just to show how I ran this code:</p><p>EXCEPTION HANDLING Rajika Tandon Page 18 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>There exist various potential problems that could cause program units to not execute properly. To avoid these problems, we make need to handle the exceptions in an appropriate manner such that the program becomes "bulletproof" so that it can continue operating in the presence of errors or terminate gracefully without loss of data.</p><p>Oracle has some inbuilt exceptions but the error messages they produce, are not user-friendly, and there is no way to recover from them. To solve this problem, Oracle has implemented a technique to except and handle errors (situations that should not occur) using an architecture referred to as exception handling. Oracle supports both pre-defined and user-defined exceptions.</p><p>This topic is vast and I just want to introduce you to user-defined exceptions at this point in time.</p><p>Oracle has provided a simple method for users to implement their own custom, user-defined, exceptions. The steps involved are to:</p><p> declare an exception variable using the EXCEPTION datatype,  check for the error condition using a decision control structure,  raise an exception condition using the RAISE command,  transfer control to the exception handling section,  and handle the exception.</p><p>Note that I suffix all the user defined execptions by _EX which is a good practice to follow. This way you can differentiate between predefined and user-defined exceptions.</p><p>Syntax: Declare an exception variable using DECLARE the EXCEPTION datatype</p><p>MY_ERROR_EX EXCEPTION; Check for the error condition BEGIN </p><p>IF some condition</p><p>THEN </p><p>RAISE MY_ERROR_EX Raise the error (transfer control to the END IF; exception handler) </p><p>Other program commands;</p><p>EXCEPTION /* exception section */ Handle the error in an appropriate WHEN MY_ERROR_EX manner THEN some program commands;</p><p>Rajika Tandon Page 19 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>END;</p><p>Let’s analyze the following records in the Student table. As we all know, the valid value for GPA should be >=0 and <4.0</p><p>But what if some ignorant data feeder entered -3.0 ! And there is no check constraint on the column as well (bad design). Such situations are exceptional cases which needs to be handled by the code you write to make it more robust. </p><p>Let us analyze the last procedure we wrote, and include exception handling in it.</p><p>CREATE OR REPLACE PROCEDURE SshipCurConditionExProc /* I am not giving any parameter as I am hardcoding gpa < 3 in the code */ IS CURSOR studCur IS SELECT * FROM Student WHERE studGPA < 3.0;</p><p> studRec studCur%ROWTYPE; /* a variable to hold the individual row fetched */ INVALID_GPA_EX EXCEPTION; /* when gpa is <0 */</p><p>BEGIN OPEN studCur; LOOP FETCH studCur INTO studRec; EXIT WHEN studCur%NOTFOUND;</p><p>Rajika Tandon Page 20 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>IF studRec.studGPA < 0 THEN RAISE INVALID_GPA_EX; END IF;</p><p>/* else display a record fetched */ DBMS_OUTPUT.PUT_LINE('Student ID = ' || studRec.studID); DBMS_OUTPUT.PUT_LINE('Student Name = ' || studRec.studName); DBMS_OUTPUT.PUT_LINE('Student GPA = ' || studRec.studGPA); DBMS_OUTPUT.PUT_LINE('***************************************'); END LOOP;</p><p>/* if no student is with a GPA < 3.0, i.e. no records found */ IF studCur%ROWCOUNT = 0 THEN RAISE NO_DATA_FOUND; -- Oracle defined exception END IF;</p><p>CLOSE studCUR;</p><p>EXCEPTION WHEN NO_DATA_FOUND THEN /* oracle defined exception */ DBMS_OUTPUT.PUT_LINE('No students with <3 GPA found.. Exceptional Students.. :)’);</p><p>WHEN INVALID_GPA_EX THEN DBMS_OUTPUT.PUT_LINE('GPA cannot be negative!’);</p><p>WHEN OTHERS THEN /* default exception */ DBMS_OUTPUT.PUT_LINE('Unknown exception.’);</p><p>END; / exec SshipCurConditionExProc(); or exec SshipCurConditionExProc;</p><p>Rajika Tandon Page 21 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3</p><p>From the above screenshot, you can see that when the program encountered the exceptional case, it jumped to the exception section, and executed the exception which was raised.</p><p>Note: WHEN OTHERS …..is a like the default exception, i.e. when an exception occurred but does not belong to any one of the mentioned exceptions, then this will be raised. It should be mentioned in the last after all other exceptions else you’ll get:</p><p>Rajika Tandon Page 22 CSE 781 Data Base Management Systems, Summer ’09 Lecture 3 COMPARISON BETWEEN PROCEDURES & FUNCTIONS</p><p>By now you must be in a good position to write and execute anonymous and stored procedures as well as functions. But you might be having several doubts in your mind as to what is the difference between the procedures and functions are ? Well, before looking at the explanation below, think what all you saw in a function and not in a procedure and the other way round, by visualizing the syntaxes of both. Also, in what situations you’ll require a procedure or a function and when is one preferred over the other. </p><p>PROCEDURES FUNCTIONS</p><p>Execute as a PL/SQL statement Invoke as part of an expression </p><p>Do not contain RETURN clause in the header Must contain a RETURN clause in the header</p><p>Can return none, one, or many values Must return a single value</p><p>Can contain a RETURN statement Must contain at least one RETURN statement</p><p>Rajika Tandon Page 23</p>

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    23 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us