Lect 7 - 8 - 9 - Database Programming With PLSQL
Lect 7 - 8 - 9 - Database Programming With PLSQL
Lecture Notes
JS
March 4, 2020
Contents
1 Database Programming with PL/SQL 3
1.1 Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.1 Introduction to PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 Benefits of PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.3 Creating PL/SQL Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Variables in PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.1 Handling Variables in PL/SQL . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 Identifiers and Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3.1 PL/SQL Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3.2 PL/SQL Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3.3 PL/SQL Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3.4 PL/SQL Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3.5 PL/SQL Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.4 Using SQL in PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.4.1 Manipulating Data in PL/SQL . . . . . . . . . . . . . . . . . . . . . . . 9
1.4.2 Manipulating Data in PL/SQL . . . . . . . . . . . . . . . . . . . . . . . 10
1.5 Program Structures to Control Execution Flow . . . . . . . . . . . . . . . . . . 11
1.5.1 IF Statements Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.5.2 Case Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.5.3 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.6 Cursor Management in PL/SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.6.1 Implicit Cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.6.2 Explicit Cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.6.3 Question . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.7 Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.7.1 Predefined exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.7.2 Raising Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.7.3 User-defined Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.8 Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.8.1 Triggering a Trigger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.9 Procedures and Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.9.1 Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.9.2 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.10 PL/SQL Practice Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
List of Figures
1 Structure of PL/SQL Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 PL/SQL Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3 Syntax of Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4 Example of Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5 Syntax of Raised Exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
6 Example of User-defined Exception . . . . . . . . . . . . . . . . . . . . . . . . . 20
7 Syntax for creating a triger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2
1 Database Programming with PL/SQL
1.1 Fundamentals
1.1.1 Introduction to PL/SQL
Procedural Language extension to SQL:
• Allows basic program logic and control flow to be combined with SQL statements.
PL/SQL is used to write the procedural code, and embed SQL data-accessing statements within
the PL/SQL code. The PL/SQL code uses variables, cursors, and conditional logic.
Characteristics of PL/SQL are:
Modularized Program Development The basic unit in a PL/SQL program is a block. All
PL/SQL programs consist of blocks. You can think of these blocks as modules and you
can “modularize” these blocks in a sequence, or nest them in other blocks. Modularized
program development has the following advantages:
3
Improved Performance PL/SQL allows you to logically combine multiple SQL statements
as one unit or block. The application can send the entire block to the database instead
of sending the SQL statements one at a time. This significantly reduces the number of
database calls (consider a database with several million records).
Integration With Oracle Tools PL/SQL is integrated in Oracle tools, such as Oracle Forms
Developer, Oracle Report Builder, and Application Express.
Portability PL/SQL is integrated in Oracle tools, such as Oracle PL/SQL programs can run
anywhere an Oracle server runs, regardless of the operating system and the platform.
PL/SQL programs do not need to be tailored for different operating systems and plat-
forms.
You can write portable program packages and create libraries that can be reused on
Oracle databases in different environments. You can even anticipate those differences
and establish instructions to run a specific way given a specific environment.
Every PL/SQL statement ends with a semicolon (;). PL/SQL blocks can be nested within
other PL/SQL blocks using BEGIN and END. Here is the basic structure of a PL/SQL block:
[DECLARE]
4
–declarations
BEGIN
–statements
[EXCEPTION]
–exceptions
END;
Examples:
No declaration or exception sections, execution only
BEGIN
DBMS_OUTPUT.PUT_LINE(’PL/SQL is easy!’);
END;
/
The end; line signals the end of the PL/SQL block. To run the code from SQL command
line, you may need to type / at the beginning of the first blank line after the last line of the
code.
• Reusability
5
All PL/SQL variables must be declared in the declaration section before referencing them
in the PL/SQL block. The purpose of a declaration is to allocate storage space for a value,
specify its data type, and name the storage location so that you can reference it. You can
declare variables in the declarative part of any PL/SQL block, subprogram, or package.
Syntax for declaring variables:
Variables are assigned a memory location inside the DECLARE section. Variables can be
assigned a value at the same time. This process is called initializing.
DECLARE
v_counter INTEGER := 0;
BEGIN
v_counter := v_counter + 1;
DBMS_OUTPUT.PUT_LINE(v_counter);
END;
After a variable is declared, you can use it in the executable section of a PL/SQL block. For
example, in the following block, the variable v myname is declared in the declarative section of
the block. You can access this variable in the executable section of the same block.
DECLARE
v_myname VARCHAR2(20);
BEGIN
v_myname := ’John’;
DBMS_OUTPUT.PUT_LINE(’My name is: ’|| v_myname);
END;
6
1.3.2 PL/SQL Delimiters
A delimiter is a symbol with a special meaning. The table in Figure 2, shows a list of delimiters
in PL/SQL:
7
DECLARE
...
v_annual_sal NUMBER (9,2);
BEGIN -- Begin the executable section
/* Compute the annual salary based on
the monthly salary input from the user */
v_annual_sal := v_monthly_sal * 12;
END; -- This is the end of the block
gives PL/SQL variable my name whatever type was declared for the ename column in
emp table.
• %rowtype - A variable can be declared with %rowtype that is equivalent to a row of a
table i.e. record with several fields. The result is a record type in which the fields have
the same names and types as the attributes of the relation.
For example :
DECLARE
Emp_rec emp1%ROWTYPE;
8
This makes variable emp rec be a record with fields name and salary, assuming that the
relation has the schema emp1(name, salary). The initial value of any variable, regardless
of its type, is NULL.
Declaration of a constant is similar to declaring a variable except that the keyword constant
must be added to the variable name and a value assigned immediately. Thereafter, no further
assignments to the constant are possible, while the constant is within the scope of the PL/SQL
block.
• Comparison operators are binary, meaning they work with two operands. Examples of
comparison operators are the greater than (>) ,less than(<) and equal(=) signs ,among
others.
• The lone character operator is a double pipe(||) that joins two strings together, concate-
nating the operands.
The INTO clause is mandatory and occurs between the SELECT and FROM clauses. It is
used to specify the names of PL/SQL 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.
DECLARE
v_country_name wf_countries.country_name%TYPE;
BEGIN
SELECT country_name INTO v_country_name
FROM wf_countries WHERE country_id= 359;
DBMS_OUTPUT.PUT_LINE(’ The country name is :
9
’||v_country_name);
END;
Return the sum of the salaries for all the employees in the specified department.
DECLARE
v_sum_sal NUMBER(10,2);
v_deptno NUMBER NOT NULL := 60;
BEGIN
SELECT SUM(salary) -- group function
INTO v_sum_sal FROM employees
WHERE department_id = v_deptno;
DBMS_OUTPUT.PUT_LINE (’The sum of salary is ’
|| v_sum_sal);
END;
Delete rows that belong to department 10 from the COPY EMP table.
DECLARE
v_deptno employees.department_id%TYPE := 10;
BEGIN
DELETE FROM copy_emp WHERE department_id = v_deptno;
END;
Insert or update rows in the copy emp table to match the employees table.
10
BEGIN
MERGE INTO copy_emp c
USING employees e
ON (e.employee_id = c.employee_id)
WHEN MATCHED THEN
UPDATE SET
c.first_name = e.first_name,
c.last_name = e.last_name,
[Link] = [Link],
. . .
WHEN NOT MATCHED THEN
INSERT VALUES(e.employee_id, e.first_name, e.last_name, [Link]);
END;
Example 1
DECLARE
v_myage NUMBER:=31;
BEGIN
IF v_myage < 11 THEN
DBMS_OUTPUT.PUT_LINE(’ I am a child ’);
ELSE
DBMS_OUTPUT.PUT_LINE(’ I am not a child ’);
END IF;
END;
11
v_bonus := 100;
END IF;
UPDATE employee SET salary = salary + v_bonus WHERE employee_id = v_emp_id;
END;
/
Example
DECLARE
v_grade CHAR(1) := ’A’;
v_appraisal VARCHAR2(20);
BEGIN
v_appraisal :=
CASE v_grade
WHEN ’A’ THEN ’Excellent’
WHEN ’B’ THEN ’Very Good’
WHEN ’C’ THEN ’Good’
ELSE ’No such grade’
END;
DBMS_OUTPUT.PUT_LINE (’Grade: ’|| v_grade ||
’ Appraisal ’ || v_appraisal);
END;
1.5.3 Loops
Loops are mainly used to execute statements repeatedly until an EXIT condition is reached.
PL/SQL provides three ways to structure loops to repeat a statement or a sequence of state-
ments multiple times. These are: basic loops, FOR loops, and WHILE loops.
Basic Loop:
A basic loop allows the execution of its statements at least once, even if the EXIT condition is
already met upon entering the loop. Without the EXIT statement, the loop would be infinite.
Syntax:
LOOP
statement1;
. . .
EXIT WHEN condition;
12
END LOOP;
Example
DECLARE
sum INTEGER := 0;
BEGIN
LOOP
sum := sum + 1;
IF sum > 10 THEN
EXIT;
END IF;
END LOOP;
END;
WHILE Loops:
You can use the WHILE loop to repeat a sequence of statements until the controlling condition is
no longer TRUE. The condition is evaluated at the start of each iteration. The loop terminates
when the condition is FALSE or NULL. If the condition is FALSE or NULL at the start of the
loop, then no further iterations are performed.
WHILE condition
LOOP
statement1;
statement2;
. . .
END LOOP;
Example
DECLARE
n_counter NUMBER :=0;
BEGIN
WHILE n_counter < 10
LOOP
DBMS_OUTPUT.PUT_LINE( ’Counter : ’ || n_counter );
n_counter := n_counter + 1;
END LOOP;
END;
FOR Loops FOR loops have the same general structure as the basic loop. In addition,
they have a control statement before the LOOP keyword to set the number of iterations that
PL/SQL performs.
FOR counter IN [REVERSE]
13
lower_bound..upper_bound
LOOP
statement1;
statement2;
. . .
END LOOP;
Examples
DECLARE
Lcntr NUMBER(2);
LCalc NUMBER;
BEGIN
FOR Lcntr IN 1..20
LOOP
LCalc := Lcntr * 31;
END LOOP;
END;
DECLARE
Lcntr NUMBER(2);
LCalc NUMBER;
BEGIN
FOR Lcntr IN REVERSE 1..15
LOOP
LCalc := Lcntr * 31;
END LOOP;
END;
• Implicit cursors: Defined automatically by Oracle for all SQL data manipulation state-
ments, and for queries that return only one row. An implicit cursor is always automatically
named “SQL.”
• Explicit cursors: Defined by the PL/SQL programmer for queries that return more than
one row.
14
• %FOUND - Returns TRUE if an INSERT, UPDATE, or DELETE statement affected
one or more rows or a SELECT INTO statement returned one or more rows. Otherwise,
it returns FALSE.
• %ISOPEN Always returns FALSE for implicit cursors, because Oracle closes the SQL
cursor automatically after executing its associated SQL statement.
Any SQL cursor attribute will be accessed as sql%attribute name as shown below in the exam-
ple.
Delete rows that have the specified department id from the copy emp table. Print the number
of rows deleted.
DECLARE
v_deptno copy_emp.department_id%TYPE := 50;
BEGIN
DELETE FROM copy_emp WHERE department_id = v_deptno;
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ’ rows deleted.’);
END;
Update several rows in the COPY EMP table. Print the number of rows updated.
DECLARE
v_sal_increase [Link]%TYPE := 800;
BEGIN
UPDATE copy_emp SET salary = salary + v_sal_increase
WHERE job_id = ’ST_CLERK’;
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT ||’ rows updated.’);
END;
• It is the only way in PL/SQL to retrieve more than one row from a table.
• Each row is fetched by a separate program statement, giving the programmer more control
over the processing of the rows.
1. DECLARE : Defines the name and structure of the cursor together with the SELECT
statement.
2. OPEN : Executes the query and the number of rows to be returned is determined.
3. FETCH : Loads the row addressed by the cursor pointer into variables and moves the
cursor pointer on to the next row ready for the next fetch.
15
4. CLOSE : Releases the data within the cursor and closes it.
The following example uses an explicit cursor to obtain the country name and national
holiday for countries in East Africa.
DECLARE
CURSOR wf_holiday_cursor IS
SELECT country_name, national_holiday_date
FROM wf_countries where region_id IN(30,34,35,36,37);
v_country_name wf_countries.country_name%TYPE;
v_holiday wf_countries.national_holiday_date%TYPE;
BEGIN
OPEN wf_holiday_cursor;
LOOP
FETCH wf_holiday_cursor INTO v_country_name, v_holiday;
EXIT WHEN wf_holiday_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_country_name||’ ’||v_holiday);
END LOOP;
CLOSE wf_holiday_cursor;
END;
Retrieve the employee id and last name columns of the employees working in the department
with a department id of 50.
DECLARE
CURSOR emp_cursor IS
SELECT employee_id, last_name FROM employees
WHERE department_id =50;
v_empno employees.employee_id%TYPE;
v_lname employees.last_name%TYPE;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_empno, v_lname;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( v_empno ||’ ’||v_lname);
END LOOP;
END;
%ROWTYPE is convenient for processing the rows of the active set because you can simply
fetch into the record.
DECLARE
CURSOR emp_cursor IS
SELECT * FROM employees WHERE department_id = 30;
v_emp_record emp_cursor%ROWTYPE;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_emp_record;
EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_record.employee_id|| ’ - ’
||v_emp_record.last_name);
END LOOP;
CLOSE emp_cursor;
END;
16
Cursors and %ROWTYPE: Another Example
DECLARE
CURSOR emp_dept_cursor IS
SELECT first_name, last_name, department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id;
v_emp_dept_record emp_dept_cursor%ROWTYPE;
BEGIN
OPEN emp_dept_cursor;
LOOP
FETCH emp_dept_cursor INTO v_emp_dept_record;
EXIT WHEN emp_dept_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_emp_dept_record.first_name ||’ -
’||v_emp_dept_record.last_name
||’ - ’||v_emp_dept_record.department_name);
END LOOP;
CLOSE emp_dept_cursor;
END;
DECLARE
CURSOR empcur IS
SELECT employee_id, salary
FROM my_employees
WHERE salary <= 20000 FOR UPDATE NOWAIT;
v_emp_rec empcur%ROWTYPE;
BEGIN
OPEN empcur;
LOOP
FETCH empcur INTO v_emp_rec;
EXIT WHEN empcur%NOTFOUND;
UPDATE my_employees SET salary = v_emp_rec.salary*1.1
WHERE CURRENT OF empcur;
END LOOP;
CLOSE empcur;
COMMIT;
END;
The optional NOWAIT keyword tells the Oracle server not to wait if any of the requested rows
have already been locked by another user. Control is immediately returned to your program
so that it can do other work before trying again to acquire the lock. If you omit the NOWAIT
keyword, then the Oracle server waits indefinitely until the rows are available.
The WHERE CURRENT OF clause is used in conjunction with the FOR UPDATE clause
to refer to the current row (the most recently FETCHed row) in an explicit cursor. The
WHERE CURRENT OF clause is used in the UPDATE or DELETE statement, whereas the
FOR UPDATE clause is specified in the cursor declaration.
1.6.3 Question
Consider the following table:
Customer(CustId, CustName, TotalPurchases, Discount)
Create a cursor as follows:
• The cursor fetches customers from the table, calculates customers discount according to
17
the following formula:
if total purchases are equal or above 100,000 then discount is 40%.
if below 100,000 then discount is 10%
• Display the custid, custname, total purchases and discount of each customer.
1. Predefined exception : Oracle predefined errors which are associated with specific error
codes.
2. User-defined exception : Declared by the user and raised when specifically requested
within a block. You can associate a user-defined exception with an error code if you wish.
Syntax for Exception Handling The General Syntax for exception handling is as shown in
Figure 3. Here, you can list down as many as exceptions you want to handle. The default
exception will be handled using WHEN others THEN:
18
in PL/SQL select command). If no rows are selected from SELECT statement then WHEN
NO DATA FOUND exception is used and for more than one row WHEN TOO MANY ROWS
exception is used.
Example Let us write some simple code (see Figure 4) to illustrate the concept. The program
displays the name and address of a customer whose ID is given. If there is no customer with ID
value 8 in the database, the program raises the run-time exception NO DATA FOUND, which
is captured in EXCEPTION block.
1.8 Triggers
Triggers are stored programs, which are automatically executed or fired when some events
occur. Triggers are, in fact, written to be executed in response to any of the following events:
19
Figure 5: Syntax of Raised Exception
20
DOWN).
Triggers could be defined on the table, view, schema, or database with which the event is
associated. You can use triggers to:
• Modify table data when DML statements are issued against views
• CREATE [OR REPLACE] TRIGGER trigger name: Creates or replaces an existing trig-
ger with the trigger name.
• {BEFORE | AFTER | INSTEAD OF}: This specifies when the trigger would be executed.
The INSTEAD OF clause is used for creating trigger on a view.
• {INSERT [OR] | UPDATE [OR] | DELETE}: This specifies the DML operation.
• [OF col name]: This specifies the column name that would be updated.
• [ON table name]: This specifies the name of the table associated with the trigger.
• [REFERENCING OLD AS o NEW AS n]: This allows you to refer new and old values
for various DML statements, like INSERT, UPDATE, and DELETE.
• [FOR EACH ROW]: This specifies a row level trigger, i.e., the trigger would be executed
for each row being affected. Otherwise the trigger will execute just once when the SQL
statement is executed, which is called a table level trigger.
• WHEN (condition): This provides a condition for rows for which the trigger would fire.
This clause is valid only for row level triggers.
Examples of triggers:
Trigger inserts a row of user details into the logging table whenever an SQL statement updates
a salary of an employee
employees(eno, ename, salary)
log table(user id, logon date)
CREATE OR REPLACE TRIGGER log_sal_change_trigg
AFTER UPDATE OF salary ON employees
BEGIN
INSERT INTO log_table (user_id, logon_date)
VALUES (USER, SYSDATE);
END;
21
Figure 7: Syntax for creating a triger
This statement trigger automatically inserts a row into a logging table every time a DML
operation is successfully executed on the DEPARTMENTS table.
log dept table (which user, when done)
CREATE OR REPLACE TRIGGER log_dept_changes
AFTER INSERT OR UPDATE OR DELETE ON DEPARTMENTS
BEGIN
INSERT INTO log_dept_table (which_user, when_done) VALUES (USER, SYSDATE);
END;
This trigger allows INSERTs into the EMPLOYEES table during normal working days (Monday
through Friday), but prevent INSERTs on the weekend (Saturday and Sunday).
CREATE OR REPLACE TRIGGER secure_emp
BEFORE INSERT ON employees
BEGIN
IF TO_CHAR(SYSDATE,’DY’) IN (’SAT’,’SUN’) THEN RAISE_APPLICATION_ERROR(-20500,
’You may insert into EMPLOYEES’ ||’ table only during business hours’);
END IF;
END;
Using conditions
CREATE OR REPLACE TRIGGER secure\_emp
BEFORE INSERT OR UPDATE OR DELETE ON employees
BEGIN
IF TO_CHAR(SYSDATE,’DY’) IN (’SAT’,’SUN’)
THEN IF DELETING THEN RAISE_APPLICATION_ERROR (-2050
1,’You may delete from EMPLOYEES’ ||’ table only during business hours’);
ELSIF INSERTING THEN RAISE_APPLICATION_ERROR (-20502,’You may insert into
EMPLOYEES
’ ||’ table only during business hours’);
ELSIF UPDATING THEN RAISE_APPLICATION_ERROR (-20503,’You may update EMPLOYEES
’ ||’ table only during business hours’);
END IF;
END IF;
END;
22
CREATE OR REPLACE TRIGGER audit_emp_values
AFTER DELETE OR INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
INSERT INTO audit_emp(user_name, time_stamp, id,
old_last_name, new_last_name, old_title,
new_title, old_salary, new_salary)
VALUES (USER, SYSDATE, :OLD.employee_id,
:OLD.last_name, :NEW.last_name, :OLD.job_id,
:NEW.job_id, :[Link], :[Link]);
END;
Trigger prevents employees who are not a President or Vice-President from having a salary of
more than $15000.
CREATE OR REPLACE TRIGGER restrict_salary
BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
IF NOT (:NEW.job_id IN (’AD_PRES’, ’AD_VP’))
AND :[Link] > 15000 THEN
RAISE_APPLICATION_ERROR (-20202,
’Employee cannot earn more than $15,000.’);
END IF;
END;
INSERT INTO employees (employee id, last name, first name, email, hire date, job id, salary,
department id)
VALUES (300, ’Smith’, ’Rob’, ’RSMITH’, SYSDATE,’IT PROG’, 4500, 60);
Output: ORA-20500: You may insert into EMPLOYEES table only during busi-
ness hours.
ORA-06512: at “USVA TEST SQL01 [Link] EMP”, line 4
ORA 04088: error during execution of trigger ‘USVA TEST SQL01 [Link] EMP’
2. VALUES (300, ’Smith’, ’Rob’, ’RSMITH’, SYSDATE, ’IT PROG’, 4500, 60);
• Easy maintenance: Modifications need only be done once to improve multiple applications
and minimize testing.
23
• Code reuse: Subprograms are located in one place. When compiled and validated, they
can be used and reused in any number of applications.
• Improved data security: Indirect access to database objects is permitted by the granting
of security privileges on the subprograms. By default, subprograms run with the privileges
of the subprogram owner, not the privileges of the user.
• Data integrity: Related actions can be grouped into a block and are performed together
(“Statement Processed”) or not at all.
• Improved performance: You can reuse compiled PL/SQL code that is stored in the shared
SQL area cache of the server. Subsequent calls to the subprogram avoid compiling the
code again. Also, many users can share a single copy of the subprogram code in memory.
• Improved code clarity: By using appropriate names and conventions to describe the action
of the routines, you can reduce the need for comments, and enhance the clarity of the
code.
1.9.1 Procedures
Syntax for creating a procedure:
CREATE [OR REPLACE] PROCEDURE procedure_name
[(parameter1 [mode] datatype1,
parameter2 [mode] datatype2, ...)]
IS|AS
[local_variable_declarations; ]
BEGIN -- actions;
END [procedure_name];
In the following example, the add dept procedure inserts a new department with the de-
partment id 280 and department name ST-Curriculum. The procedure declares two variables,
v dept id and v dept name, in the declarative section.
CREATE OR REPLACE PROCEDURE add_dept IS
v_dept_id dept.department_id%TYPE;
v_dept_name dept.department_name%TYPE;
BEGIN
v_dept_id :=280;
v_dept_name :=’ST-Curriculum’;
INSERT INTO dept(department_id,department_name)
VALUES(v_dept_id,v_dept_name);
DBMS_OUTPUT.PUT_LINE(’Inserted ’||SQL%ROWCOUNT ||’row’);
END;
• Another procedure
• Anonymous block
• A calling application
The example shows a procedure with two parameters. Running this first statement creates the
raise salary procedure in the database. The second example executes the procedure, passing
the arguments 176 and 10 to the two parameters.
24
CREATE OR REPLACE PROCEDURE raise_salary (
emp_id NUMBER, -- formal parameter
amount NUMBER -- formal parameter
) IS
BEGIN
UPDATE employees SET salary = salary + amount
WHERE employee_id = emp_id;
END raise_salary;
25
query_emp(178, a_emp_name, a_emp_sal);
DBMS_OUTPUT.PUT_LINE(’Name: ’ || a_emp_name);
DBMS_OUTPUT.PUT_LINE(’Salary: ’ || a_emp_sal);
END;
Create a procedure with OUT parameters to retrieve information about an employee. The
procedure accepts the value 178 for employee ID and retrieves the name and salary of the
employee with ID 178 into the two OUT parameters. The query emp procedure has three formal
parameters. Two of them are OUT parameters that return values to the calling environment.
The procedure accepts an employee ID value through the pid parameter. The a emp name
and a emp sal variables are populated with the information retrieved from the query into their
two corresponding OUT parameters. Make sure that the data type for the actual parameter
variables used to retrieve values from OUT parameters has a size large enough to hold the data
values being returned.
1.9.2 Functions
A function is a named PL/SQL block (a subprogram) that can accept optional IN parameters
and must return a single output value. Functions are stored in the database as schema objects
for repeated execution. Syntax:
CREATE [OR REPLACE] FUNCTION function_name
[(parameter1 [mode1] datatype1, ...)]
RETURN datatype IS|AS
[local_variable_declarations;]
BEGIN
-- actions;
RETURN expression;
END [function_name];
Example:
CREATE OR REPLACE FUNCTION get_sal
(p_id employees.employee_id%TYPE)
RETURN NUMBER IS
v_sal [Link]%TYPE := 0;
BEGIN
SELECT salary
INTO v_sal
FROM employees
WHERE employee_id = p_id;
RETURN v_sal;
END get_sal
26
1.10 PL/SQL Practice Questions
1. Write a PL/SQL blocks for the following:
(a) Using case statement, the block accepts a number 1 to 4 and outputs it in words
(i.e 1 - one), else it should output invalid number.
(b) Display the first 5 even numbers making use of basic loop, for loop and while
loop.
(c) Creates a table temp(number, Description). The program inserts the numbers 1
to 10, along with a description of whether the number is even or odd. Check if the
table exists with its data.
NB: The program should check whether a number is even or odd.
(a) Retrieve Regno, Name of students belonging to Computer Science department and
display the list on screen.
(b) Retrieve Regno, name, fees of students belonging to Physics department. Thereafter
update the fees by 10% of the current fees.
(a) create a trigger which ensures that before a row is inserted into the student table,
the fees amount must be above 200,000. Otherwise displays an error message.
(b) Create a trigger which ensures that when an update or delete is done on the student
table, it inserts a row in a student log table, the user name of the person who has
updated/deleted and date of update/delete.
(a) Create a parameterized procedure which takes regno as input, computes pending fees
for the student. Call the procedure in an anonymous block and display the student
regno, name and pending fees.
(b) Create a parameterized function which takes regno as input, computes and returns
pending fees for the student. Call the function in an anonymous block and display
the student regno and pending fees.
5. Using the insurance database, which you already created, answer the questions which fol-
low. Driver(Driver id:String, Name:String, City:String, Phone no:String, Country:String,
Gender:String)
Car(Regno:String, Make:String, Year:String)
Accident(Report no:int, Accident date:Date, Location:String)
Owns(Driver id:String, Regno:String)
Participated(Driver id:String, Regno:String, Report no:int, Damage amount:int)
(a) Write a PL/SQL block to display the name and city of a driver whose id is ’D101’.
(b) Write a PL/SQL block to check how many accidents have occurred in the location
of “Jinja”. If 5 or more accidents have occurred then display a message ”there is
need for more awareness on road safety”. Otherwise, ”Drivers are conscious of road
safety”.
27
(c) Write a cursor which will display accident details and damage amounts for [Link].
Assume [Link] has been involved in more than one accident.
(d) Write a procedure to increase the damage amount of a given driven driver’s id. Test
the procedure by using another PL/SQL block.
(e) Write a function to return the total number of drivers who got accidents in a given
location. Test the function by using another PL/SQL block.
(f) Define a trigger before update of damage amount for each row of Participated table,
to insert a record of the row in Participated table, the new value of damage amount
and date of update into a table “audit Participated”. Test the trigger. Hint: Re-
member to create the table “audit Participated” with the required columns.
28