SA0951a Oracle Practical: PL/SQL Cursors, Procedures, Functions
SA0951a Oracle Practical: PL/SQL Cursors, Procedures, Functions
Functions
DECLARE
CURSOR high_salaries IS SELECT snum, surname,salary FROM personnel
where salary > 30000;
v_snum personnel.snum%TYPE;
v_surname personnel.surname%TYPE;
v_salary personnel.salary%TYPE;
BEGIN
OPEN high_salaries;
LOOP
FETCH high_salaries INTO v_snum,v_surname,v_salary;
EXIT when high_salaries%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(v_snum ||' '||v_surname||' '|| v_salary);
END LOOP;
CLOSE high_salaries;
END;
a) The cursor code below is designed to update personnel salaries based on where they
work. Only there are lots of errors in it for you to sort out. Good luck, look very, very
carefully and try to learn by interpreting the error messages you get. Sometimes they
ARE useful! If you don’t get it all sorted right away you can always come back to it.
Go onto the next question if you get stuck as you can persevere with this in your own
time.
declare
03/02/2019 Page 1
cursor c1 select snum, city from personnel p, branch b where p.div=b.div;
v_city b.city%type ;
v_snum personnel.snum%type;
v_salary_1 number=30000;
v_salary_2 number(4):=25000;
v_salary_3 number:=20000;
v_salary personnel.salary%type;
begin
open c1;
loop
fetch c1 into v_snum, v_city;
exit where c1%NOTFOUND;
If v_city='LONDON' then v_salary:=v_salary1;
elsif v_city='BRISTOL' then v_salary:=v_salary_2;
else v_sal:=v_salary_3;
end if;
update my_personnel set salary = v_salary where snum=v_snum;
endloop;
close ;
end;
A block which outputs the average result and current date and user is given below.
DECLARE
average NUMBER(7,2);
Begin
SELECT AVG(salary) INTO average FROM personnel;
DBMS_OUTPUT.PUT_LINE ('As of ' || SYSDATE);
DBMS_OUTPUT.PUT_LINE ('The average salary is ' || Average);
DBMS_OUTPUT.PUT_LINE ('Prepared by ' || USER);
END;
Run it.
Say you now want to get the average salary just for branch 10.
The code you need is
03/02/2019 Page 2
CREATE PROCEDURE average_salary IS
Today DATE := SYSDATE;
Average NUMBER(7,2);
Begin
SELECT AVG(salary) INTO Average FROM personnel WHERE div=10;
DBMS_OUTPUT.PUT_LINE ('As of ' || Today);
DBMS_OUTPUT.PUT_LINE ('Average salary for branch 10 is ' || Average);
DBMS_OUTPUT.PUT_LINE ('Prepared by ' || USER);
END;
Do the CREATE PROCEDURE process again, adding the WHERE clause as shown
above.
You will probably get the message
" ERROR at line 1: ORA-00955: name is already used by an existing object"
Why?
………………………………………………………………………………..
To solve this problem, you could DROP the procedure first. But there is a better way:
Use
CREATE OR REPLACE PROCEDURE …….
at the top and try again.
Note: The words OR REPLACE after CREATE make sure that if the procedure exists
already, you can edit it.
03/02/2019 Page 3
Task 6: Declaring Procedures within procedures and calling them
Study the code below and write down the output you would expect the program to
produce, then execute the main procedure and see if you were right. You’ll need to
understand the MOD function in particular. Basically it returns a zero if the result of a
division by a specified number is an integer. Be clear about how the control is being
passed to and fro between the procedures
Task 7: Function
Study the function and procedure below. They are written to calculate the total mileage
for a given division name.
The procedure accepts a division name and then calls a function to calculate the total
mileage, which then returns the result to the procedure. The result is printed to the
screen.
Your task is to ANNOTATE the code with comments so that you understand what the
code is doing.
03/02/2019 Page 4
RETURN number
IS
v_aveMiles Transport.Mileage%type;
BEGIN
SELECT avg(Mileage)
INTO v_aveMiles FROM Transport
WHERE div=i_div;
RETURN v_aveMiles;
END get_aveMiles;
You can TEST the function on its own using the following code:
You can now test the Procedure (which calls the function you have already tested) using
the following:
Execute avemiles(‘ADMIN’)
So now you can play around with the code by trying it out on different Division Names to
see if it works.
What would you change if you wanted to calculate the maximum mileage for any
division?
Study the code below which uses functions embedded within a main
function to do some fairly trivial arithmetic.
Again, see if you can work out what the output from the program function would be by
tracing control within the code and record it below. Pay particular attention to the
RETURN.
03/02/2019 Page 5
is
begin
return v_1*v_2;
end multiply;
function divide
return number
is
begin
return v_1/v_2;
end divide;
begin
if op='+' then v_return:=Add;
elsif op='-' then v_return:=subtract;
elsif op='*' then v_return:=multiply;
elsif op ='/' then v_return:=divide;
else v_return:=null;
end if;
return v_return;
end calculate;
To test the program you can use Oracle’s DUAL dummy table in SELECT statements.
For instance, try:
This should call the function and perform the arithmetic for you. Make sure you
understand how the ‘calling’ is achieved in the above statement.
Try passing various parameters to test the code works. Try passing a zero for a division
for example!
03/02/2019 Page 6
end calc_stats;
Create a routine that could be run each month to insert pension contribution details into
a PENSIONS table. So create the table first.
You’ll need to declare variables for all of your prompts and for anchoring variables to the
datatypes in the PENSIONS table for the insertion of data.
SELECT surname, first name, salary, tax(35000,500) from dual; (the two parameters
being salary and bonus respectively).
Things you need to know and incorporate (read carefully and try to work out the formulae
from the information given):
22% of the upper limit + 40% of the difference between the taxable salary and
the upper limit.
03/02/2019 Page 7