Download - Plsql Samp

Transcript

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:1

PARTIII

Create ProgramsUsing PL/SQL

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:02 AM

Color profile: Generic CMYK printer profileComposite Default screen

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:2

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:02 AM

Color profile: Generic CMYK printer profileComposite Default screen

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:3

CHAPTER8

Introduction to PL/SQL

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:02 AM

Color profile: Generic CMYK printer profileComposite Default screen

Storing and retrieving information is just one part of any real-lifeapplication. Even the simplest applications need to do some processingthat is difficult or impossible using SQL alone. Just think of how complexthe computations are when the government’s share of your earningsneeds to be computed every year! OK, maybe you want to think of

another example instead. In any case, SQL alone isn’t up to the task.

What Is PL/SQL?You may ask why SQL doesn’t have features that allow you to do more sophisticatedcomputations on data. The reason is partly historical: SQL came into existence as adatabase query language (Structured Query Language) and has evolved and beenoptimized for doing exactly that: querying databases. Different providers of databasesoftware have agreed to certain SQL standards, but they did not agree on how to giveusers more sophisticated SQL-oriented programming capabilities. Thus, each databasesoftware provider has come up with proprietary or semi-proprietary products. Oraclecalls its solution PL/SQL. You can think of this as standing for “Programming Languagefor SQL.”

In this chapter you will be introduced to the basics of PL/SQL. You will learn thedifference between SQL, SQL*Plus®, and PL/SQL. You will also start writing simplePL/SQL procedures, as well as functions using basic PL/SQL constructs like variables,loops, and cursors. Then you will learn about the important art of handling errors ina way the user can easily understand.

If you just started reading in this chapter and have not done any of the exercisesin the preceding chapters, you will need to create the sample tables built in priorchapters before you can do the exercises in this chapter. To accomplish this, enterthe following SQL commands:

L 8-1 DROP TABLE plsql101_purchase;DROP TABLE plsql101_product;DROP TABLE plsql101_person;DROP TABLE plsql101_old_item;DROP TABLE plsql101_purchase_archive;

CREATE TABLE plsql101_person (person_code VARCHAR2(3) PRIMARY KEY,first_name VARCHAR2(15),last_name VARCHAR2(20),hire_date DATE)

;

4 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:4

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:03 AM

Color profile: Generic CMYK printer profileComposite Default screen

CREATE INDEX plsql101_person_name_indexON plsql101_person(last_name, first_name);

ALTER TABLE plsql101_personADD CONSTRAINT plsql101_person_unique UNIQUE (

first_name,last_name,hire_date)

;

INSERT INTO plsql101_person VALUES('CA', 'Charlene', 'Atlas', '01-FEB-05');

INSERT INTO plsql101_person VALUES('GA', 'Gary', 'Anderson', '15-FEB-05');

INSERT INTO plsql101_person VALUES('BB', 'Bobby', 'Barkenhagen', '28-FEB-05');

INSERT INTO plsql101_person VALUES('LB', 'Laren', 'Baxter', '01-MAR-05');

INSERT INTO plsql101_person VALUES('LN', 'Linda', 'Norton', '01-JUN-06');

CREATE TABLE plsql101_product (product_name VARCHAR2(25) PRIMARY KEY,product_price NUMBER(4,2),quantity_on_hand NUMBER(5,0),last_stock_date DATE)

;

ALTER TABLE plsql101_product ADD CONSTRAINT positive_quantity CHECK(quantity_on_hand IS NOT NULLANDquantity_on_hand >=0)

;

INSERT INTO plsql101_product VALUES('Small Widget', 99, 1, '15-JAN-06');

INSERT INTO plsql101_product VALUES('Medium Wodget', 75, 1000, '15-JAN-05');

INSERT INTO plsql101_product VALUES('Chrome Phoobar', 50, 100, '15-JAN-06');

INSERT INTO plsql101_product VALUES('Round Chrome Snaphoo', 25, 10000, null);

Chapter 8: Introduction to PL/SQL 5

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:5

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:03 AM

Color profile: Generic CMYK printer profileComposite Default screen

INSERT INTO plsql101_product VALUES('Extra Huge Mega Phoobar +',9.95,1234,'15-JAN-07');

INSERT INTO plsql101_product VALUES ('Square Zinculator',45, 1, TO_DATE('December 31, 2005, 11:30 P.M.',

'Month dd, YYYY, HH:MI P.M.'))

;INSERT INTO plsql101_product VALUES (

'Anodized Framifier', 49, 5, NULL);INSERT INTO plsql101_product VALUES (

'Red Snaphoo', 1.95, 10, '31-DEC-04');INSERT INTO plsql101_product VALUES (

'Blue Snaphoo', 1.95, 10, '30-DEC-04');

CREATE TABLE plsql101_purchase (product_name VARCHAR2(25),salesperson VARCHAR2(3),purchase_date DATE,quantity NUMBER(4,2))

;

ALTER TABLE plsql101_purchaseADD PRIMARY KEY (product_name,

salesperson,purchase_date)

;

ALTER TABLE plsql101_purchaseADD CONSTRAINT reasonable_date CHECK(

purchase_date IS NOT NULLANDTO_CHAR(purchase_date, 'YYYY-MM-DD') >= '2003-06-30')

;

ALTER TABLE plsql101_purchaseADD CONSTRAINT plsql101_purchase_fk_product FOREIGN KEY

(product_name) REFERENCES plsql101_product;

ALTER TABLE plsql101_purchaseADD CONSTRAINT plsql101_purchase_fk_person FOREIGN KEY

(salesperson) REFERENCES plsql101_person;

CREATE INDEX plsql101_purchase_productON plsql101_purchase(product_name);

6 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:6

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:03 AM

Color profile: Generic CMYK printer profileComposite Default screen

CREATE INDEX plsql101_purchase_salespersonON plsql101_purchase(salesperson);

INSERT INTO plsql101_purchase VALUES('Small Widget', 'CA', '14-JUL-06', 1);

INSERT INTO plsql101_purchase VALUES('Medium Wodget', 'BB', '14-JUL-06', 75);

INSERT INTO plsql101_purchase VALUES('Chrome Phoobar', 'GA', '14-JUL-06', 2);

INSERT INTO plsql101_purchase VALUES('Small Widget', 'GA', '15-JUL-06', 8);

INSERT INTO plsql101_purchase VALUES('Medium Wodget', 'LB', '15-JUL-06', 20);

INSERT INTO plsql101_purchase VALUES('Round Chrome Snaphoo', 'CA', '16-JUL-06', 5);

INSERT INTO plsql101_purchase VALUES ('Small Widget', 'CA', '17-JUL-06', 1)

;

UPDATE plsql101_productSET product_price = product_price * .9WHERE product_name NOT IN (

SELECT DISTINCT product_nameFROM plsql101_purchase)

;

CREATE TABLE plsql101_purchase_archive (product_name VARCHAR2(25),salesperson VARCHAR2(3),purchase_date DATE,quantity NUMBER(4,2))

;

INSERT INTO plsql101_purchase_archive VALUES('Round Snaphoo', 'BB', '21-JUN-04', 10);

INSERT INTO plsql101_purchase_archive VALUES('Large Harflinger', 'GA', '22-JUN-04', 50);

INSERT INTO plsql101_purchase_archive VALUES('Medium Wodget', 'LB', '23-JUN-04', 20);

INSERT INTO plsql101_purchase_archive VALUES('Small Widget', 'ZZ', '24-JUN-05', 80);

INSERT INTO plsql101_purchase_archive VALUES('Chrome Phoobar', 'CA', '25-JUN-05', 2);

INSERT INTO plsql101_purchase_archive VALUES('Small Widget', 'JT', '26-JUN-05', 50);

Chapter 8: Introduction to PL/SQL 7

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:7

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:03 AM

Color profile: Generic CMYK printer profileComposite Default screen

Describe PL/SQLPL/SQL provides the features that allow you to do sophisticated information processing.Let’s say that every night you want to transfer the day’s business summary into a day’ssummary table—PL/SQL packages can help you do this. Or, you want to know whetheryou need to arrange for extra supplies for purchase orders that are really large—PL/SQLprovides triggers that will notify you as soon as any order placed is found to be largerthan certain limits decided by you. In addition, you can use PL/SQL stored proceduresto compute your employees’ performance to help you decide about bonuses. Plus,a nice PL/SQL function can calculate the tax withholdings for an employee.

PL/SQL lets you use all the SQL data manipulation, cursor control, and transactioncontrol commands, as well as all the SQL functions and operators. So, you canmanipulate Oracle data flexibly and safely. Also, PL/SQL fully supports SQL datatypes.This reduces the need to convert data passed between your applications and thedatabase. PL/SQL also supports dynamic SQL, an advanced programming techniquethat makes your applications more flexible and versatile. Your programs can buildand process SQL data definition, data control, and session control statements“on the fly” at run time.

Before we proceed to learn more about some of these power tools, I will give yousome idea about how SQL, SQL*Plus®, and PL/SQL relate to each other.

Who’s Who in SQL, SQL*Plus®, and PL/SQLThink of a restaurant. You go in and hopefully a well-trained waiter or waitress waitson you. You look through the menu and place an order. The waiter writes down yourorder and takes it into the kitchen. The kitchen is huge—there are many chefs andassistants. You can see a lot of food—cooked, partially cooked, and uncooked—stored in the kitchen. You can also see people with various jobs: they take the foodin and out of storage, prepare a particular type of food (just soups or just salads, forinstance), and so forth. Depending on what menu items you ordered, the waiter takesthe order to different chefs. Some simple orders are completed by one chef, while morecomplex orders may require help from assistants, or even multiple chefs. In addition,some orders are standard items—a waiter can just tell a chef “mushroom pizza”—while other orders are custom creations requiring a detailed list of exactly whatingredients you want.

Now alter this scenario a little. Think of an Oracle database as the restaurant’skitchen, with SQL*Plus® serving as the waiter taking our orders—scripts, commands,or programs—to the kitchen, or database. Inside the kitchen are two main chefs:SQL and PL/SQL. Like a waiter, SQL*Plus® knows what orders it can process on itsown, as well as what orders to take to specific chefs. In the same way that a waitercan bring you a glass of water without having to get it from a chef, SQL*Plus® canadjust the width of the lines shown on its screen without needing to go to thedatabase.

8 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:8

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:03 AM

Color profile: Generic CMYK printer profileComposite Default screen

The commands or programs you enter and execute at the SQL*Plus® prompt aresomewhat like your special-order pizza. For custom orders the chefs have to do somethinking each time. Just like the chef has the recipe for cheese pizza stored in his orher brain, you can have PL/SQL store “recipes” for your favorite orders. These storedPL/SQL elements are called triggers, stored functions, stored procedures, and packages.You will learn more about them soon.

As I mentioned earlier, some orders require more than one chef to prepare them.Most of the interesting and useful database applications you create will have SQL andPL/SQL working together, passing information back and forth between them to processa script or program. In a restaurant, after an order is prepared it goes to a waiter tobe taken to your table. Similarly, when SQL and PL/SQL process commands, the resultsgo to SQL*Plus® (or a custom front-end form) to be displayed to the user.

Stored Procedures, Stored Functions, and TriggersPL/SQL procedures, functions, and triggers all help you build complex businesslogic easily and in a modular fashion (meaning piece by piece, with the piecesbeing reusable by other pieces). Storing these in the Oracle server provides twoimmediate benefits: they can be used over and over with predictable results, andthey execute very rapidly because server operations involve little or no networktraffic.

Stored ProceduresA stored procedure is a defined set of actions written using the PL/SQL language.When a procedure is called, it performs the actions it contains. The procedure isstored in the database, which is the reason it is called a stored procedure.

A stored procedure can execute SQL statements and manipulate data in tables.It can be called to do its job from within another PL/SQL stored procedure, storedfunction, or trigger. A stored procedure can also be called directly from an SQL*Plus®

prompt. As you read through the pages that follow, you will learn how to employeach of these methods for calling a stored procedure.

A procedure consists of two main parts: the specification and the body. Theprocedure specification contains the procedure’s name and a description of itsinputs and outputs. The inputs and outputs we are talking about are called theprocedure’s formal parameters or formal arguments. If a call to a procedure includescommand-line parameters or other inputs, those values are called actual parametersor actual arguments.

Now let’s take a look at some samples of procedure specifications. (Remember,the specification doesn’t contain any code; it just names the procedure and definesany inputs and outputs the procedure can use.)

L 8-2 run_ytd_reports

Chapter 8: Introduction to PL/SQL 9

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:9

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:03 AM

Color profile: Generic CMYK printer profileComposite Default screen

This simple specification contains only the procedure’s name. It has no parameters.

L 8-3 increase_prices (percent_increase NUMBER)

A value can be passed to this procedure when it is called. Within the procedure,the value will be addressed as PERCENT_INCREASE. Note that the value’s datatypehas been specified: NUMBER.

L 8-4 increase_salary_find_tax (increase_percent IN NUMBER := 7,sal IN OUT NUMBER,tax OUT NUMBER)

Here we have a procedure with three formal parameters. The word IN after aparameter’s name indicates that the procedure can read an incoming value fromthat parameter when the procedure is called. The word OUT after a parameter’sname indicates that the procedure can use that parameter to send a value back towhatever called it. Having IN OUT after a parameter’s name says that the parametercan bring a value into the procedure and also be used to send a value back out.

The INCREASE_PERCENT parameter in this example gets assigned a default valueof 7 by including := 7 after the datatype. Because of this, if the procedure is calledwithout specifying any increase percentage, it will increase the salary given by 7percent and calculate the tax based on the new salary.

NOTEDatatypes in a procedure cannot have sizespecifications. For instance, you can specify thata parameter is a NUMBER datatype, but not aNUMBER(10,2) datatype.

The procedure body is a block of PL/SQL code, which you will learn about inthe section entitled Structure of a PL/SQL Block.

Stored FunctionsA PL/SQL function is similar to a PL/SQL procedure: It has function specification anda function body. The main difference between a procedure and a function is that afunction is designed to return a value that can be used within a larger SQL statement.

For instance, think for a moment about a function designed to calculate thepercentage difference between two numbers. Ignoring the code that would performthis calculation, the function specification would look like this:

L 8-5 calc_percent(value_1 NUMBER,value_2 NUMBER) return NUMBER

10 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:10

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:03 AM

Color profile: Generic CMYK printer profileComposite Default screen

This function accepts two numbers as input, referring to them internally asVALUE_1 and VALUE_2. Once the body of this function was written, it could bereferred to in an SQL statement in the following way:

L 8-6 INSERT INTO employee VALUES (3000, CALC_PERCENT(300, 3000));

TriggersA trigger is a PL/SQL procedure that gets executed automatically whenever someevent defined by the trigger—the triggering event—happens. You can write triggersthat fire when an INSERT, UPDATE, or DELETE statement is performed on a table;when DDL statements are issued; when a user logs on or off; or when the databasestarts, encounters an error, or shuts down.

Triggers differ from PL/SQL procedures in three ways:

� You cannot call a trigger from within your code. Triggers are calledautomatically by Oracle in response to a predefined event.

� Triggers do not have a parameter list.

� The specification for a trigger contains different information than aspecification for a procedure.

You will learn more about triggers and their uses in Chapter 9.

Stored Procedures and SQL ScriptsWhile SQL scripts reside on your computer’s hard disk, stored procedures reside withinyour Oracle database. An SQL script contains a series of SQL commands that areexecuted, one by one, when you invoke the script. In contrast, a stored procedure cancontain flow-control commands allowing it to iterate through a particular section ofcode over and over; branch to another code section when particular situations occur;and respond to error conditions in a way you specify.

Structure of a PL/SQL BlockIn this section you will learn about the PL/SQL basic block. Everything in PL/SQL thatactually does work is made up of basic blocks. After learning about the basic blocks,you will see examples of complete procedures, functions, and triggers.

A PL/SQL basic block is made up of four sections: the header section, an optionaldeclaration section, the execution section, and the optional exception section.

An anonymous block is a PL/SQL block with no header or name section, hencethe term anonymous block. Anonymous blocks can be run from SQL*Plus® and theycan be used within PL/SQL functions, procedures, and triggers. Recall that PL/SQLprocedures, functions, and triggers are all made up of basic blocks themselves.What this means is that you can have a basic block within a basic block. Perhapsthe best way to begin to understand a basic block is to examine a sample. First,

Chapter 8: Introduction to PL/SQL 11

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:11

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:04 AM

Color profile: Generic CMYK printer profileComposite Default screen

type the following command so that information printed by programs can be madevisible in SQL*Plus®:

L 8-7 set serveroutput on

Now try the following sample code to create an anonymous block. Compare yourresults with Figure 8-1.

L 8-8 DECLARENum_a NUMBER := 6;Num_b NUMBER;

BEGINNum_b := 0;Num_a := Num_a / Num_b;Num_b := 7;dbms_output.put_line(' Value of Num_b ' || Num_b);

EXCEPTIONWHEN ZERO_DIVIDE

THENdbms_output.put_line('Trying to divide by zero');dbms_output.put_line(' Value of Num_a ' || Num_a);dbms_output.put_line(' Value of Num_b ' || Num_b);

END;/

12 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:12

FIGURE 8-1. Example of an anonymous PL/SQL block

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:04 AM

Color profile: Generic CMYK printer profileComposite Default screen

Header SectionThe header section for a block varies based on what the block is part of. Recall thatprocedures, functions, triggers, and anonymous blocks are made up of basic blocks.In fact, each has one basic block that makes up its body. This body block may containmore basic blocks inside it. The header for this top-level basic block of a function,procedure, or trigger is the specification for that function, procedure, or trigger. Foranonymous blocks, the header contains only the keyword DECLARE. For labeledblocks, the header contains the name of the label enclosed between << and >>,followed by the keyword DECLARE, as shown in the following code:

L 8-9 <<just_a_label>>DECLARE

Block labels help make it easier to read code. In a procedure using nested blocks(blocks inside other blocks), you can refer to an item in a specific block by precedingthe item’s name with the name of the block (for example, block_label.item_label).

Declaration SectionThe declaration section is optional. When used, it begins after the header section andends at the keyword BEGIN. The declaration section contains the declarations forPL/SQL variables, constants, cursors, exceptions, functions, and procedures thatwill be used by the execution and exception sections of the block. All variable andconstant declarations must come before any function or procedure declarations withinthe declaration section. You will learn more about PL/SQL variables and constantsin the following section of the same name (“PL/SQL Variables and Constants”).A declaration tells PL/SQL to create a variable, constant, cursor, function, or procedureas specified in the declaration.

The declaration section (beginning with the word DECLARE) in the example shownin Figure 8-1 tells PL/SQL to create two number type variables called Num_a andNum_b. It also assigns a value of 6 by default to Num_a.

When a basic block has finished its run, everything declared within the declarationsection stops existing. Things declared within the declaration section of a basic blockcan be used only within the same block. Thus, after running the example block inSQL*Plus® there is no way to pass Num_a to another PL/SQL procedure. Num_a andNum_b just go out of existence as soon as the block finishes its run. However, if youcall a PL/SQL function or procedure within the execution or exception section of theblock, you can pass Num_a and Num_b to them as actual parameters.

The long and short of the story is, whatever is in the declaration section is the privateproperty of the block—to be used by and visible only to itself. Thus, what is in thedeclaration section of the block only lives as long as the block. In technical terms,Num_a and Num_b are said to have the scope of the block in which they are declared.The scope of the block starts at the beginning of the block’s declaration section andends at the end of its exception section.

Chapter 8: Introduction to PL/SQL 13

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:13

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:04 AM

Color profile: Generic CMYK printer profileComposite Default screen

Execution SectionThe execution section starts with the keyword BEGIN and ends in one of two ways.If there is an exception section, the execution section ends with the keyword EXCEPTION.If no exception section is present, the execution section ends with the keyword END,followed optionally by the name of the function or procedure, and a semicolon. Theexecution section contains one or more PL/SQL statements that are executed when theblock is run. The structure for the executable section is shown below:

BEGINone or more PL/SQL statements

[exception section]END [name of function or procedure];

The executable section, in the example block of Figure 8-1, contains three PL/SQLassignment statements. The assignment statement is the most commonly seen statementin PL/SQL code. The first statement assigns the value of zero to Num_b. The colonfollowed by an equal sign (:=) is the assignment operator. The assignment operatortells PL/SQL to compute whatever is on its right-hand side and place the result inwhatever is on its left-hand side.

The second statement assigns Num_a the value of Num_a divided by Num_b. Notethat after this statement is executed successfully the value of Num_a will be changed.

The third statement assigns the value of 7 to Num_b.

Exception SectionIt is possible that during the execution of PL/SQL statements in the execution section,an error will be encountered that makes it impossible to proceed with the execution.These error conditions are called exceptions. The procedure’s user should be informedwhen an exception occurs and told why it has occurred. You may want to issue auseful error to the user or you may want to take some corrective action and retrywhatever the procedure was attempting before the error happened. You may wantto roll back changes done to the database before the error occurred.

For all these situations PL/SQL helps you by providing exception handlingcapabilities. Exceptions are so important for good applications that I have a specialsection at the end of this chapter where you will learn more about them (see“Exceptions” within the “Error Handling” section). As an introduction, the following isthe structure for the exception section:

EXCEPTIONWHEN exception_nameTHEN

actions to take when this exception occursWHEN exception_nameTHEN

actions to take when this exception occurs

14 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:14

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:04 AM

Color profile: Generic CMYK printer profileComposite Default screen

The exception section begins at the keyword EXCEPTION and ends at the end ofthe block. For each exception there is a WHEN exception_name statement that specifieswhat should be done when a specific exception occurs. Our example has three funny-looking statements that have the effect of making text display on your SQL*Plus®

screen. A little more information is needed to understand what they are doing, but wewill leave the details for Chapter 9. The DBMS_OUTPUT package and PUT_LINEprocedure are part of the Oracle database; together they cause text to display on yourSQL*Plus® screen one line at a time.

All the statements between the statement that causes the exception and theexception section will be ignored. So, in the case of the example block in Figure 8-1,the assigning of 7 to Num_b is not executed. You can verify this by looking at the valuefor Num_b that the example code prints out.

When a statement in the exception section deals with an exception, we refer tothat action as exception handling.

Detecting that the error occurred and which exception best describes it and thentaking appropriate steps to inform PL/SQL about it so as to make it possible for PL/SQLto find the exception section for that exception is called raising exception. In theexample code in Figure 8-1, the exception is raised by PL/SQL on its own by detectingthat there is an attempt at division by zero. PL/SQL has a predefined name for thisexception—ZERO_DIVIDE. In many situations the error must be detected by yourcode, not by PL/SQL.

Create a Simple PL/SQL ProcedureWe have all the ingredients to try writing a complete PL/SQL procedure. You knowabout the basic block and you have learned about procedure specifications. Now trythe following code:

L 8-10 CREATE PROCEDURE my_first_proc ISgreetings VARCHAR2(20);

BEGINgreetings := 'Hello World';dbms_output.put_line(greetings);

END my_first_proc;/

The syntax for creating a stored procedure is the following:

CREATE PROCEDURE procedure_specification IS procedure_body

In our sample, the procedure specification is just the name of the procedure,and the body is everything after it up to the last semicolon. For functions, you willuse the keyword FUNCTION instead of PROCEDURE:

CREATE FUNCTION function_specification IS function_body

Chapter 8: Introduction to PL/SQL 15

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:15

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:04 AM

Color profile: Generic CMYK printer profileComposite Default screen

The forward slash ( / ) tells SQL*Plus® to go ahead and process the commandsin the program. You can re-create the same procedure or function by changing theCREATE command to CREATE OR REPLACE. This will destroy the old definition ofthe procedure or function and replace it with the new one. If there is no old definitionit will simply create a new one.

CREATE OR REPLACE PROCEDURE procedure_specificationIS procedure_body

Now let us see how this procedure can be called from SQL*Plus®:

L 8-11 set serveroutput onEXECUTE my_first_proc;

SERVEROUTPUT ON allows you to see the printed output. The EXECUTEcommand actually executes the procedure. You can call the procedure from within ananonymous block as follows. Compare your results with those shown in Figure 8-2.

L 8-12 BEGINmy_first_proc;

END;/

Call Procedures and FunctionsA procedure or function may or may not have formal parameters with default values.In fact, it may not have any formal parameters at all. For each case, the way theprocedure or function is called is different. However, the following applies regardlessof the parameters:

� The datatypes for the actual parameters must match or should be convertibleby PL/SQL to the datatypes of corresponding formal parameters.

� Actual parameters must be provided for all formal parameters that do nothave default values.

When calling a function without any parameters, you can just use the name withor without parentheses, like the following:

procedure_name();or procedure_name;

The same syntax is used when dealing with a function, except a semicolon willnot be used when the function is called as part of an expression.

16 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:16

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:05 AM

Color profile: Generic CMYK printer profileComposite Default screen

When a procedure has formal parameters with default values and when theyare all at the end of the list of formal parameters in the procedure specification,the procedure may be called without specifying values for the last few formalparameters for which default values exist. However, all the formal parameters forwhich actual parameters are being supplied at call time must be listed before allof the formal parameters for which no actual parameters are being supplied. The callwill then look like the following:

procedure_name(actual_param1,actual_param2,...actual_paramN);

N may be less than or equal to the number of formal parameters for the procedureand N must be greater than or equal to the number of formal parameters for whichdefault values do not exist.

Chapter 8: Introduction to PL/SQL 17

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:17

FIGURE 8-2. Simple “Hello World” PL/SQL procedure

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:05 AM

Color profile: Generic CMYK printer profileComposite Default screen

When the default-valued formal parameters are not the last parameters in thespecification, or when you wish to avoid having PL/SQL figure out which actualparameter corresponds to which formal parameter using its order in the list, you canspecifically tell PL/SQL which actual parameter is for which formal parameter usingthe following syntax:

procedure_name(formal_param1 => actual_param1,formal_param2 => actual_param2,...)

;

This is called named notation for calling functions and procedures. The earliernotation is called positional notation as the parameters are matched by their positionin the list.

The same calling methods apply to functions. Functions, however, can appearwithin other expressions and may not have any semicolon at the end. You will seean example for named notation in the next section. It is possible to mix two notations,but the positional list must precede the notational list in the call.

PL/SQL Variables and ConstantsYou have seen some examples of PL/SQL variables in previous sections. Now we willdiscuss them in greater detail. Variables are essentially containers with name tags.They can contain or hold information or data of different kinds. Based on the kindof data they can hold, they have different datatypes and to distinguish them from oneanother they have names. Just as oil comes in a bottle and flour in a paper bag, PL/SQLwill store numbers in variables of the NUMBER datatype and text in variables of theCHAR or VARCHAR2 datatypes. Taking it a step further, imagine the refrigerator inyour company’s break room. It’s filled with brown paper bags that contain your lunchand the lunches of your co-workers. How will you find your noontime feast amongstall the other bags? Right! You’d put your name on the bag. Variables are given names,too, in order to avoid confusion. Further, if your lunch consisted of only bananas youmay eat them and put the peels back into the brown paper bag. Now the contents ofthe bag have changed. Similarly, the contents of variables can be changed during theexecution of PL/SQL statements.

Declare PL/SQL VariablesThe syntax for declaring a variable in PL/SQL is either of the following:

variable_name data_type [ [NOT NULL] := default_value_expression];variable_name data_type [ [NOT NULL] DEFAULT default_value_expression];

18 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:18

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:05 AM

Color profile: Generic CMYK printer profileComposite Default screen

variable_name is any valid PL/SQL identifier. A valid PL/SQL identifier has thefollowing properties:

Up to 30 characters long and has no white space of any form in it (as spaceor tabs).

� Made up of letters, digits 0 to 9, underscore (_), dollar ($), and pound (#) signs.

� Starts with a letter.

� Is not the same as a PL/SQL or an SQL reserved word, which has specialmeaning for PL/SQL or SQL. For example, a variable name cannot be BEGIN.BEGIN has a special meaning telling PL/SQL that here starts the beginningof a basic block execution section.

The use of NOT NULL requires that the variable have a value and, if specified,the variable must be given a default value.

When a variable is created it can be made to have a value specified by the defaultvalue expression. It is just a shorthand way to assign values to variables.

You already know about SQL datatypes—NUMBER, VARCHAR2, and DATE.PL/SQL shares them with SQL. PL/SQL has additional datatypes that are not in SQL.For a complete list, please refer to Oracle PL/SQL references.

Declare PL/SQL ConstantsThe syntax for declaring a constant is the following:

variable_name data_type CONSTANT := constant_value_expression;

Unlike variables, constants must be given a value and that value cannot changeduring the life or scope of the constant. Constants are very useful for enforcing safeand disciplined code development in large and complex applications. For example,if you want to ensure that the data passed to a PL/SQL procedure is not modified bythe procedure, you can make that data a constant. If the procedure tries to modify it,PL/SQL will return with an exception.

Assign Values to VariablesThere are three ways a variable can get its value changed. First is the assignment ofa valid expression to it using the PL/SQL assignment operator. You have seen a numberof examples of this kind. The syntax is the following:

variable_name := expression ;

Chapter 8: Introduction to PL/SQL 19

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:19

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:05 AM

Color profile: Generic CMYK printer profileComposite Default screen

Second, a variable can be passed as the actual parameter corresponding tosome IN OUT or OUT formal parameter when calling a PL/SQL procedure. After theprocedure is finished the value of the variable may change. The following exampleshows the named notation for calling procedures. Refer to Figure 8-3 for theexpected output.

L 8-13 CREATE PROCEDURE hike_prices (old_price NUMBER,percent_hike NUMBER := 5,new_price OUT NUMBER)

ISBEGIN

new_price := old_price + old_price * percent_hike / 100;END hike_prices;/

20 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:20

FIGURE 8-3. Assign values to PL/SQL variables by using them as actualparameters

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:05 AM

Color profile: Generic CMYK printer profileComposite Default screen

The following procedure shows the variables changing their values:

L 8-14 set serveroutput onDECLARE

price_to_hike NUMBER(6,2) := 20;hiked_price NUMBER(6,2) := 0;

BEGINdbms_output.put_line('Price before hike ' || price_to_hike);dbms_output.put_line('hiked_price before hike ' || hiked_price);hike_prices (old_price => price_to_hike,

new_price => hiked_price);dbms_output.put_line('price_to_hike after hike ' || price_to_hike);dbms_output.put_line('hiked_price after hike ' || hiked_price);

END;/

The following is a quick example with Figure 8-4 showing the results:

L 8-15 set serveroutput onDECLAREproduct_quant NUMBER;BEGIN

SELECT quantity_on_handINTO product_quantFROM plsql101_productWHERE product_name = 'Small Widget';

dbms_output.put_line ('Small Widget ' || product_quant);END;/

product_quant is assigned the value equal to the quantity of small widgets.

Chapter 8: Introduction to PL/SQL 21

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:21

FIGURE 8-4. Assign values to PL/SQL variables using SQL

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:05 AM

Color profile: Generic CMYK printer profileComposite Default screen

Use VariablesVariables are the very basic units of PL/SQL programs. They are used to hold resultsof computations, to return values from function calls, as actual parameters for callingfunctions and procedures, and so on. Variables should be used to make yourapplication clean and easy to read, thereby creating a lower maintenance, moreefficient program.

Suppose you want to perform a number of calculations using the current quantityof small widgets—compare it with the quantity from three months ago, or to thequantity of medium widgets. By using the variable to hold the value, you avoid thedelay that would come from getting the quantity from the table again and again.

By naming variables in a way that makes sense to you, you can make your codeeasy to read and understand. The same principle applies when you use variables tohold the results of some very complex expressions instead of repeating the expressionsin the code in multiple places.

Control Structures in PL/SQLMany times you want to do one thing if something is true and something else if it isnot true. For example, if a purchase order exceeds a certain dollar amount you wouldlike to take 5 percent off the order, and maybe 10 percent off if the order exceedssome other amount. This kind of logic may be required inside your application thatprints out the final invoice for your customers. This is conditional processing of data.Based on the condition, different parts of the code need to be executed.

Recall the case where you need to compute income tax for each employee. Youneed to complete a function for each employee, such as finding the earnings and filingstatus, and then apply the correct formula to find the tax. The correct formula differsfor each employee based on filing status and all of the other factors. This is an exampleof an iterative operation.

PL/SQL provides you with the ability to do conditional and iterative processing.The constructs it provides are said to cause change of program flow and so controlthe flow of the execution.

IF StatementThe syntax for an IF statement is as follows:

IF condition_1 THENactions_1;

[ELSIF condition_2 THENactions_2;]

...[ELSE

actions_last;]END IF;

22 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:22

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:06 AM

Color profile: Generic CMYK printer profileComposite Default screen

actions_1 to actions_last represent one or more PL/SQL statements. Each set ofstatements gets executed only if its corresponding condition is true. When one of theIF conditions is determined to be true, the rest of the conditions are not checked.

Enter the following example and see that your results match those of Figure 8-5:

L 8-16 -- Compute discounts on orders.-- Input order amount. Returns discount amount (zero for wrong inputs).CREATE FUNCTION compute_discounts (order_amt NUMBER)RETURN NUMBER IS

small_order_amt NUMBER := 400;large_order_amt NUMBER := 1000;small_disct NUMBER := 1;large_disct NUMBER := 5;

BEGINIF (order_amt < large_order_amt

ANDorder_amt >= small_order_amt)

THENRETURN (order_amt * small_disct / 100);

ELSIF (order_amt >= large_order_amt)THEN

RETURN (order_amt * large_disct / 100);ELSE

RETURN(0);END IF;

END compute_discounts;/

This function will give a 1 percent discount for orders between 400 and 1000and a 5 percent discount on orders above 1000. It will return zero for all other amountsincluding wrong values. For example, someone may try to use a negative value fororder_amt, which is meaningless.

Observe at the start how the function is clearly documented. You should alwaysconsider all possibilities when writing your code and either clearly state in yourdocumentation what you are going to do about error conditions or, if the conditionsare severe enough, give appropriate error messages. Suppose in our case—howeverunimaginable it is—that this function may be called with a negative value for theorder_amt, we have documented what the function will do in such a case.

You can test the function by calling it in an anonymous block. Be sure you haveserveroutput on. Refer once again to Figure 8-5 for this example.

L 8-17 set serveroutput onDECLARE

tiny NUMBER := 20;med NUMBER := 600;big NUMBER := 4550;wrong NUMBER := -35;

BEGINdbms_output.put_line (' Order AND Discount ');

Chapter 8: Introduction to PL/SQL 23

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:23

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:06 AM

Color profile: Generic CMYK printer profileComposite Default screen

dbms_output.put_line (tiny || ' ' || compute_discounts(tiny));dbms_output.put_line (med || ' ' || compute_discounts (med));dbms_output.put_line (big || ' ' || compute_discounts (big));dbms_output.put_line (wrong || ' ' || compute_discounts (wrong));

END;/

24 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:24

FIGURE 8-5. Example of an IF statement

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:06 AM

Color profile: Generic CMYK printer profileComposite Default screen

LoopsPL/SQL provides three different iteration constructs. Each allows you to repeatedlyexecute a set of PL/SQL statements. You stop the repeated executions based on somecondition.

LOOPThe syntax for the LOOP construct is as follows:

<<loop_name>>LOOP

statements;EXIT loop_name [WHEN exit_condition_expression];statements;

END LOOP ;

All the statements within the loop are executed repeatedly. During each repetitionor iteration of the loop, the exit condition expression is checked for a positive value ifthe WHEN condition is present. If the expression is true, then the execution skips allstatements following the EXIT and jumps to the first statement after END LOOP withinthe code. No more iterations are done. If the WHEN condition is not present, the effectis to execute statements between LOOP and EXIT only once. You will obviously bedoing something illogical if you are not using the WHEN condition. After all, the ideaof a loop is to potentially loop through the code.

Try out the following loop example and compare the results with Figure 8-6.It simply prints out the first ten numbers.

As usual, do not forget to set serveroutput on to see the output.

L 8-18 set serveroutput onDECLARE

just_a_num NUMBER := 1;BEGIN

<<just_a_loop>>LOOP

dbms_output.put_line(just_a_num);EXIT just_a_loopWHEN (just_a_num >= 10);

just_a_num := just_a_num + 1;END LOOP;

END;/

Each iteration increments the variable just_a_num by 1. When 10 is reached,the exit condition is satisfied and the loop is exited.

Chapter 8: Introduction to PL/SQL 25

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:25

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:06 AM

Color profile: Generic CMYK printer profileComposite Default screen

WHILE LoopAnother type of loop is the WHILE loop. A WHILE loop is well suited for situationswhen the number of loop iterations is not known in advance, but rather is determinedby some external factor. The syntax for a WHILE loop is as follows:

WHILE while_condition_expressionLOOP

statements;END LOOP;

Practice creating a WHILE loop by entering the following code. Your resultsshould match those of Figure 8-7.

L 8-19 set serveroutput onDECLARE

just_a_num NUMBER := 1;

26 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:26

FIGURE 8-6. Example of a simple LOOP

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:06 AM

Color profile: Generic CMYK printer profileComposite Default screen

BEGINWHILE (just_a_num <= 10) LOOP

dbms_output.put_line(just_a_num);just_a_num := just_a_num + 1;

END LOOP;END;/

NOTEThe condition for the WHILE must be true every timebefore entering the loop.

FOR LoopThe FOR loop uses a counter variable, also called a loop index, to count the numberof iterations. The counter is incremented, starting from the lower limit specified, ordecremented, starting from the upper limit specified, at the end of each iteration or loop.If it is out of the range, the looping stops. The syntax for the FOR loop is as follows:

FOR counter IN [REVERSE] lower_bound .. upper_boundLOOP

statements;END LOOP;

Chapter 8: Introduction to PL/SQL 27

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:27

FIGURE 8-7. Example of a WHILE loop

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:06 AM

Color profile: Generic CMYK printer profileComposite Default screen

Now create your first FOR loop using the following code. Your results shouldmatch those of Figure 8-8.

L 8-20 set serveroutput onBEGIN

FOR just_a_num IN 1..10LOOP

dbms_output.put_line(just_a_num);END LOOP;

END;/

Now for fun and experience, try using the REVERSE command in your FOR loop.Your results should show the numbers in reverse order from 10 to 1.

CursorsThe cursor is an extremely important PL/SQL construct. It is the heart of PL/SQLand SQL cooperation and stands for “current set of records.” A cursor is a specialPL/SQL element that has an associated SQL SELECT statement. Using a cursor,

28 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:28

FIGURE 8-8. Example of a FOR loop

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:07 AM

Color profile: Generic CMYK printer profileComposite Default screen

each row of the SQL statement associated with the cursor can be processed one ata time. A cursor is declared in the declaration section of a basic block. A cursor isopened using the command OPEN and rows can be fetched using the commandFETCH. After all processing is done, the cursor is closed using the CLOSE command.Closing the cursor releases all of the system resources that were used while the cursorwas open. You can lock the rows selected by a cursor to prevent other people frommodifying them while you are using them. Closing the cursor or executing an explicitCOMMIT or ROLLBACK will unlock the rows.

PL/SQL uses hidden or implicit cursors for SQL statements within PL/SQL code.We discuss them more in Chapter 9. In this section we will focus on explicit cursors,which simply means cursors that have been assigned a name.

We will write a simple procedure that uses a cursor to compute the commissionsfor all salespersons. Before we do that, however, take a look at the syntax for anexplicit cursor.

Cursor Declaration and Cursor AttributesA cursor is declared within a PL/SQL procedure in the following manner:

CURSOR cursor_name [( [parameter1 [, parameter2 ...])][RETURN return_specification]IS

select_statement[FOR UPDATE

[OF table_or_col1[, table_or_col2 ...]

]]

;

The parameters are similar to procedure parameters, but they are all IN parameters.They cannot be OUT or IN OUT because the cursor cannot modify them. Theparameters are used in the WHERE clause of the cursor SELECT statement. The returnspecification tells what type of records will be selected by the SELECT statement.You will learn more about PL/SQL records in Chapter 9. The table_or_col is a columnname you intend to update or a table name from which you intend to delete or updaterows; it must be taken from the names of tables and columns used within the cursorSELECT statement. It is used to clearly document what may potentially be modifiedby the code that uses this cursor. The FOR UPDATE commands lock the rows selectedby the SELECT statement when the cursor is opened, and they remain locked until youclose the cursor in the ways already discussed.

A cursor has some indicators to show its state and they are called attributes ofthe cursor. The attributes are shown in Table 8-1.

Chapter 8: Introduction to PL/SQL 29

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:29

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:07 AM

Color profile: Generic CMYK printer profileComposite Default screen

PL/SQL RecordsAlthough PL/SQL records will be discussed in greater detail in Chapter 9, you’ll needto know a little something about them before we proceed. So let’s start with a briefintroduction in this chapter.

A PL/SQL record is a collection of basic types of data and can be accessed as asingle unit. You access the individual fields of the record using the record_name.field_name notation you are already familiar with for use with table columns. Records areof three types and you can declare variables of record types. The three types of recordsare the following:

� Table-Based This record has fields that match the names and types of thetable columns. So if a cursor selects the entire row—by using SELECT* fromsome_table, for example—the records it returns can be directly copied intothe variable of the table-based record type for some_table.

� Cursor-Based This record has fields that match in name, datatype, and orderto the final list of columns in the cursor’s SELECT statement.

� Programmer-Defined These are records in which you define a record type.

Use OPEN, FETCH, and CLOSE CursorThe following is the syntax for opening, fetching from, and closing a cursor:

OPEN cursor_name;FETCH cursor_name INTO record_var_or_list_of_var;CLOSE cursor_name;

30 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:30

Attribute Description

cursor_name%ISOPEN Checks if the cursor is open. It returns TRUE if thecursor cursor_name is already open.

cursor_name%ROWCOUNT The number of table rows returned by the cursorSELECT statement.

cursor_name%FOUND Checks whether the last attempt to get a recordfrom the cursor succeeded. It returns TRUE if arecord was fetched.

cursor_name%NOTFOUND Opposite of the FOUND attribute. It returns TRUEwhen no more records are found.

TABLE 8-1. Cursor Attributes

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:07 AM

Color profile: Generic CMYK printer profileComposite Default screen

When opened, a cursor contains a set of records if the cursor’s SELECT statementwas successful and resulted in fetching selected rows from the database. Each FETCHthen removes a record from the open cursor and moves the record’s contents intoeither a PL/SQL variable—of a record type that matches the record type of the cursorrecord—or into a different set of PL/SQL variables such that each variable in the listmatches in type with the corresponding field in the cursor record.

You will check if there are any more records left in the cursor before trying tofetch one from the cursor using the FOUND and NOTFOUND attributes of thecursor. Fetching from an empty cursor will fetch the last fetched record over andover again and will not give you any error. So make sure you use FOUND orNOTFOUND if you are using FETCH.

The actual processing of records from a cursor usually occurs within a loop.When writing the loop, it’s a good idea to start by checking whether a record hasbeen found in the cursor. If so, the code proceeds to perform whatever processingyou need; if not, the code exits from the loop. There is a more compact way to dothe same where PL/SQL takes care of opening, fetching, and closing without yourneeding to do it—the cursor FOR loop.

Cursor FOR LoopThe syntax for the cursor FOR loop is the following:

FOR cursor_record IN cursor_name LOOPstatements;

END LOOP;

This cursor FOR loop continues fetching records from the cursor into the cursor_record record type variable. You can use cursor_record fields to access the data withinyour PL/SQL statements in the loop. When all the records are done, the loop ends.The cursor is automatically opened and closed for your convenience by PL/SQL.

You will receive an invalid cursor message if you try to fetch from a cursor thatis not open. If you do not close cursors, you may end up eventually running into themaximum number of open cursors that the system allows.

WHERE CURRENT OFWhen the cursor is opened in order to update or delete the rows it selects, you can use

WHERE CURRENT OF cursor_name

to access the table and row corresponding to the most recently fetched record in theWHERE clause of the UPDATE or DELETE statement. For example, to reduce the pricesin the PLSQL101_PRODUCT table by 3 percent, type the following code and checkyour results against those in Figure 8-9.

Chapter 8: Introduction to PL/SQL 31

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:31

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:07 AM

Color profile: Generic CMYK printer profileComposite Default screen

L 8-21 SELECT product_name, product_priceFROM plsql101_product;

DECLARECURSOR product_cur IS

32 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:32

FIGURE 8-9. Examples of a cursor FOR loop and WHERE CURRENT OF clause

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:07 AM

Color profile: Generic CMYK printer profileComposite Default screen

SELECT * FROM plsql101_productFOR UPDATE OF product_price;

BEGINFOR product_rec IN product_curLOOP

UPDATE plsql101_productSET product_price = (product_rec.product_price * 0.97)WHERE CURRENT OF product_cur;

END LOOP;END;/

SELECT product_name, product_priceFROM plsql101_product;

Nested Loops and Cursor ExampleThe following code demonstrates complete use of cursors and loops within loopsor nested loops. Enter the following code:

L 8-22 -- This procedure computes the commissions for salespersons.-- It prints out the salesperson's code, his or her total sales,-- and corresponding commission.-- No inputs. No errors are reported and no exceptions are raised./* Logic: A cursor to create a join between PLSQL101_PRODUCT andPLSQL101_PURCHASE on PRODUCT_NAME column is done.The result is ordered by salesperson.Outer loop starts with a new salesperson and inner loopprocesses all rows for one salesperson.*/CREATE OR REPLACE PROCEDURE do_commissions IS

commission_rate NUMBER := 2 ;total_sale NUMBER := 0 ;current_person CHAR(3) := ' ' ;next_person CHAR(3) ;quantity_sold NUMBER := 0 ;item_price NUMBER := 0 ;CURSOR sales_cur IS

SELECT purc.salesperson,purc.quantity,prod.product_price

FROM plsql101_purchase purc,plsql101_product prod

WHERE purc.product_name = prod.product_nameORDER BY salesperson;

BEGINOPEN sales_cur;

Chapter 8: Introduction to PL/SQL 33

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:33

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:07 AM

Color profile: Generic CMYK printer profileComposite Default screen

LOOPFETCH sales_cur INTO

next_person, quantity_sold, item_price;WHILE (next_person = current_person

ANDsales_cur%FOUND)

LOOPtotal_sale :=

total_sale + (quantity_sold * item_price);FETCH sales_cur INTO

next_person, quantity_sold, item_price;END LOOP;IF (sales_cur%FOUND)THEN

IF (current_person != next_person)THEN

IF (current_person != ' ' )THEN

dbms_output.put_line(current_person ||' ' ||total_sale ||' ' ||total_sale * commission_rate / 100);

END IF;total_sale := quantity_sold * item_price;current_person := next_person;

END IF;ELSE IF (current_person != ' ')THEN

dbms_output.put_line(current_person ||' ' ||total_sale ||' ' ||total_sale * commission_rate / 100);

END IF;END IF;EXIT WHEN sales_cur%NOTFOUND;END LOOP;CLOSE sales_cur;

END do_commissions;/

First look at the cursor’s SELECT statement. It lists, from the PLSQL101_PURCHASEtable, the quantities of items sold. It also shows their corresponding prices from thePLSQL101_PRODUCT table. This is achieved by creating a join. The result is orderedby salesperson so that we have all of the records for a particular salesperson together.

34 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:34

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:07 AM

Color profile: Generic CMYK printer profileComposite Default screen

Once the cursor is opened and the first row is fetched, the condition for WHILEis checked. The first FETCH command for the current person has a value that cannotmatch any salesperson code; recall that its default value is a single space ( ). Therefore,the loop is skipped and we jump to the first IF statement. The IF statement checks to seeif the last FETCH command returned any records. If records were returned, a checkis made to see whether the current_person and next_person values match. If they don’tmatch, we know that the last FETCH is the start of a new salesperson and it is time toprint out the commissions for the current salesperson. Note that the first record forcurrent_person is not valid; therefore, the IF check will fail and nothing will print.

The next statement sets the value for total_sale to be equal to the cost for thevery first product. The statement after that stores the next_person value into thecurrent_person variable. Now we will be back to the first FETCH in the loop asthe loop’s EXIT condition is not yet true. This FETCH may result in the same valuefor next_person as the current_person, in which case we have more than one entry forthe current person in our list of sales. When that is the case, the WHILE loop is enteredand the cost for items is added to the total sale amount. This loop will keep addingcosts by fetching new records from the cursor until a new salesperson is identified.This process repeats over and over until there are no records left in the cursor. At thatpoint, the validity of the current_person is checked. If the current_person is valid, thenthe very last IF statement prints out sales and commissions for that person; thecommissions are calculated using the value in the commission_rate constant.

To test the procedure, enter the following commands and compare your resultswith those in Figure 8-10. The first command shows the raw records in the PLSQL101_PURCHASE table, while the second command causes the DO_COMMISSIONSprocedure to subtotal the sales in those records and calculate appropriate commissionsfor each salesperson.

L 8-23 SELECT purc.salesperson,purc.quantity,prod.product_price

FROM plsql101_purchase purc,plsql101_product prod

WHERE purc.product_name = prod.product_nameORDER BY salesperson;

set serveroutput onEXECUTE do_commissions;

Error HandlingIt is important to issue user-friendly error messages when error conditions occur.Earlier in this chapter, the section on basic PL/SQL blocks included a mention ofexceptions; now it is time to get into more detail.

Chapter 8: Introduction to PL/SQL 35

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:35

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:07 AM

Color profile: Generic CMYK printer profileComposite Default screen

ExceptionsAn exception is an error state that is activated—or raised—when a specific problemoccurs. There are many different exceptions, each relating to a different type of problem.When an exception is raised, the code execution stops at the statement that raisedthe exception, and control is passed to the exception-handling portion of the block.If the block does not contain an executable section, PL/SQL tries to find an executablesection in the enclosing basic block, which is an outer block of code surrounding theblock in which the exception was raised. If the immediate enclosing block does nothave an exception handler to accommodate the raised exception, then the searchcontinues to the next enclosing block and so on until a proper exception handler isfound or, if not found, execution is halted with an unhandled exception error.

The exception-handling portion of a block is the perfect opportunity to issuemeaningful error messages and clean up anything that could cause confusion or troublelater. A typical cleanup could involve issuing the ROLLBACK statement if an exceptionis raised during a procedure that has inserted rows into a table.

36 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:36

FIGURE 8-10. Example of nested loops

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:08 AM

Color profile: Generic CMYK printer profileComposite Default screen

Once control is passed to the exception handler, control is not returned to thestatement that caused the exception. Instead, control is passed to the enclosing basicblock at the point just after the enclosed block or procedure/function was called.

System-Defined ExceptionsYou are familiar with the ZERO_DIVIDE exception predefined by PL/SQL. There arequite a few other system-defined exceptions that are detected and raised by PL/SQLor Oracle. Table 8-2 provides a more complete list of system-defined exceptions.

Chapter 8: Introduction to PL/SQL 37

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:37

System-Defined Exception Description

CURSOR_ALREADY_OPEN Tried to open an already open cursor.

DUP_VAL_ON_INDEX Attempted to insert duplicate value in columnrestricted by unique index to be unique.

INVALID_CURSOR Tried to FETCH from cursor that was not open ortried to close a cursor that was not open.

NO_DATA_FOUND Tried to SELECT INTO when the SELECT returns norows (as well as other conditions that are outside thescope of this book).

PROGRAM_ERROR Internal error. Usually means you need to contactOracle support.

STORAGE_ERROR Program ran out of system memory.

TIME_OUT_ON_RESOURCE Program waited too long for some resource to beavailable.

TOO_MANY_ROWS SELECT INTO in PL/SQL returns more than one row.

VALUE_ERROR PL/SQL encountered invalid data conversions,truncations, or constraints on data.

ZERO_DIVIDE Attempt at division by zero.

OTHERS All other exceptions or internal errors not coveredby the exceptions defined in the basic block. Usedwhen you are not sure which named exception youare handling, but you do want to handle whicheverexception was raised.

TABLE 8-2. System-Defined Exceptions

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:08 AM

Color profile: Generic CMYK printer profileComposite Default screen

PL/SQL has two ways of showing information to a user about an error. One optionis the use of the command SQLCODE, which returns the error code. An error code isa negative value that usually equals the value of the corresponding ORA error thatwould be issued if the exception remains unhandled when an application terminates.The other option returns a text message regarding the error. Not surprisingly, thiscommand is SQLERRM. You can use both SQLCODE and SQLERRM in the exceptionhandler. Note: not all system-defined exceptions are named.

Now try the previous example again, but this time use SQLCODE and SQLERRM.Enter the following code and compare your results with those shown in Figure 8-11.

L 8-24 set serveroutput onDECLARE

Num_a NUMBER := 6;Num_b NUMBER;

BEGINNum_b := 0;Num_a := Num_a / Num_b;Num_b := 7;dbms_output.put_line(' Value of Num_b ' || Num_b);

EXCEPTIONWHEN ZERO_DIVIDE THEN

DECLAREerr_num NUMBER := SQLCODE;err_msg VARCHAR2(512) := SQLERRM;

BEGINdbms_output.put_line('ORA Error Number ' || err_num );dbms_output.put_line('ORA Error message ' || err_msg);dbms_output.put_line(' Value of Num_a is ' || Num_a);dbms_output.put_line(' Value of Num_b is ' || Num_b);

END;END;/

Programmer-Defined ExceptionsOne handy feature of PL/SQL is that it allows you to create your own exceptionconditions and names. When raising and handling your own exceptions, they mustbe named and declared just like any other PL/SQL entity.

Here is a complete example of how to name and define your own exception. Enterthe following code and compare your results with those shown in Figure 8-12:

L 8-25 set serveroutput onDECLARE

quantity1 NUMBER := -2;quantity2 NUMBER := 3;total NUMBER := 0;quantity_must_positive EXCEPTION;FUNCTION find_cost (quant NUMBER) RETURN NUMBER IS

38 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:38

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:08 AM

Color profile: Generic CMYK printer profileComposite Default screen

BEGINIF (quant > 0)THEN

RETURN(quant * 20);ELSE

RAISE quantity_must_positive;END IF;

END find_cost;BEGIN

total := find_cost (quantity2);total := total + find_cost(quantity1);

EXCEPTIONWHEN quantity_must_positiveTHEN

dbms_output.put_line('Total until now: ' || total);dbms_output.put_line('Tried to use negative quantity ');

END;/

Chapter 8: Introduction to PL/SQL 39

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:39

FIGURE 8-11. Using SQLCODE and SQLERRM for system-defined exceptions

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:08 AM

Color profile: Generic CMYK printer profileComposite Default screen

The exception is declared in the declaration section. Just like any other PL/SQLvariable declared there, the life of the exception is valid only for this block. Sincefind_cost is also in this block, or is enclosed by this block, it can use the exceptionname. If the same function was defined as, say, a stored function, then you couldnot use the same exception name.

You can use your own exceptions for application-specific exception conditionsthat otherwise cannot be detected by the system or have no meaning for thesystem. For example, the system does not know that quantities ordered must bepositive integer values. Your application should know this, however, and you canenforce it by catching values that are not positive integers as an exception whiledoing computations based on quantities. This is a very simple example, but youcan imagine and will certainly come across more complex cases in real-lifeapplications.

40 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:40

FIGURE 8-12. Programmer-defined exception

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:08 AM

Color profile: Generic CMYK printer profileComposite Default screen

SummaryThis chapter served as an introduction to the wonderful world of PL/SQL—a powerfulprogramming language that works hand in hand with SQL. We explored PL/SQLvariables. PL/SQL variables are used to hold the results of computations and to carrythose results from one computation task to another.

We discussed the aspects of the PL/SQL basic block. All PL/SQL program unitsare made up of one or more basic blocks. A basic block is made up of header,declaration, execution, and exception sections. The header section contains identifyinginformation for the block. For anonymous blocks, the header section is empty. Thedeclaration section contains declarations for variables, constants, exceptions, cursors,functions, and procedures to be used within the block’s execution and exceptionsections; if none of these are used, the declaration section will be empty. The executionsection contains PL/SQL executable statements. The execution section is not optionaland must be present to form a block. The exception section is used to handle error,or exception, conditions occurring within the execution section. This includesexceptions that may not be handled within any enclosed or nested blocks and withinfunctions or procedures called.

We discussed how to create and call functions and procedures. You learned themeaning and use of formal and actual parameters.

Recall that PL/SQL program flow control constructs allow you to conditionallyexecute a piece of code once or repeatedly. The IF statement allows conditionalexecution once. The LOOP, WHILE loop, and FOR loop allow for repeated executionof the same set of statements. Cursors are the means for PL/SQL to communicate withSQL and hence the database. The cursor FOR loop allows you to process rows oftables one at a time.

Finally, you learned how to define your own exceptions and to raise or handlethem by issuing friendly error messages. Another option is to remove what’s causingthe error and try again to create a successful program.

We have covered a lot of ground in this chapter and it has been the foundationfor Chapter 9. You are probably eager to play with PL/SQL’s powerful features. Havesome fun, and then jump right into the next chapter.

Chapter Questions1. Which of the following are true about PL/SQL procedures and functions?

A. There is no difference between the two.

B. A function has a return type in its specification and must return a valuespecified in that type. A procedure does not have a return type in itsspecification and should not return any value, but it can have a returnstatement that simply stops its execution and returns to the caller.

Chapter 8: Introduction to PL/SQL 41

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:41

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:08 AM

Color profile: Generic CMYK printer profileComposite Default screen

C. Both may have formal parameters of OUT or IN OUT modes, but afunction should not have OUT or IN OUT mode parameters.

D. Both can be used in a WHERE clause of a SQL SELECT statement.

2. Which is the correct output for a run of the following code sample?

<<outer_block>>

DECLARE

scope_num NUMBER := 3;

BEGIN

DECLARE

scope_num NUMBER := 6;

Num_a NUMBER := outer_block.scope_num;

BEGIN

dbms_output.put_line(scope_num);

dbms_output.put_line(Num_a);

END;

dbms_output.put_line(scope_num);

END;

A. 6 3 3

B. Gives error saying duplicate declaration and aborts execution

C. 3 3 3

D. 6 3 6

3. Which of the following is true about IF statements?

A. At most, one set of executable statements gets executed correspondingto the condition that is TRUE. All other statements are not executed.

B. It depends. Sometimes more than one set of statements gets executed asmultiple conditions may be TRUE and then statements for each of themshould get executed.

4. Which of the following LOOPs will be entered at least once?

A. Simple LOOP

B. WHILE loop

C. FOR loop

D. Cursor FOR loop

42 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:42

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:08 AM

Color profile: Generic CMYK printer profileComposite Default screen

5. Which one of the following is not true about exceptions?

A. Exceptions raised within the declaration section are to be handled inthe enclosing block, if you want to handle them.

B. Statements in the execution section just after the statement responsiblefor raising exceptions are executed once the exception handler hasfinished execution.

C. When the system raises exceptions and they are not handled by theprogrammer, all the committed changes made to database objects—like tables by the execution section within which the exception occurred—are not automatically rolled back by the system.

D. Exceptions raised within a called procedure not handled by the procedurewill roll back the changes done to IN OUT or OUT parameters by theprocedure before the exception occurred.

Answers to Chapter Questions1. B, C. A function has a return type in its specification and must return a

value specified in that type. A procedure does not have a return type inits specification and should not return any value, but it can have a returnstatement that simply stops its execution and returns to the caller.Both may have formal parameters of OUT or IN OUT modes, but a functionshould not have OUT or IN OUT mode parameters.

Explanation A is certainly not true. D is false because procedures do not returnvalues whereas functions do by utilizing the WHERE clause. Functions computeand return a single value, but do not modify its inputs so C is true. B is true as amatter of PL/SQL legal syntax.

2. A. 6 3 3

Explanation This is an example of scope. The outer block scope_num is overriddeninside the inner block by its own scope_num. Thus the value for scope_num insidethe inner block is 6. This inner scope_num is not visible to the outer block so once theinner block has run, the scope_num used is the outer scope_num resulting in the lastvalue of 3. To get at the outer scope_num, we use the label name inside the innerblock while assigning value to Num_a.

Chapter 8: Introduction to PL/SQL 43

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:43

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:08 AM

Color profile: Generic CMYK printer profileComposite Default screen

3. A. At most, one set of executable statements gets executed correspondingto the condition that is TRUE. All other statements are not executed.

Explanation The IF, ELSE, and ELSIF constrain the execution so that the conditionsare mutually exclusive. Only one statement can be true. When no statements are true,no statements are executed.

4. A. Simple LOOP

Explanation The simple LOOP checks the condition for exiting the loop inside theloop body so it must get inside at least once. All other loops check the condition beforeentering the loop.

5. B. Statements in the execution section just after the statement responsiblefor raising exceptions are executed once the exception handler has finishedexecution.

Explanation If not handled, exceptions will abort the execution of the executionsection and return control to the enclosing block. Therefore, the statements in theculprit execution section after the statement that raises exception will not be executed.All other choices are true.

44 Oracle Database 10g PL/SQL 101

ORACLE Series / Oracle Database 10g PL/SQL 101 / Allen / 225540-4 / Chapter 8Blind Folio 8:44

P:\010Comp\Oracle8\540-4\ch08.vpJuly 16, 2004 2:37:09 AM

Color profile: Generic CMYK printer profileComposite Default screen