Chapter 5 Practice

advertisement
Chapter 4 Practice (Volume 2)
1) Write the Procedure called Get_Job_Income that will as Input parameter accept Last Name
(in Upper case) of the employee and as Output display firstly the message about his/her First
Name, Job Id and Annual Income (incl. Commission). Then you will display just Job id and
Annual Income as Output variables. You will use previously defined Function Get_Income.
You need to take care also for situations where the Input is an invalid Last Name and if there is
more than one person with that name. You should use For Cursor Loop and test your procedure
by using BIND variables.
Here are the outputs:
VARIABLE
VARIABLE
EXECUTE
PRINT
job VARCHAR2(20)
total NUMBER
Get_Job_Income('ZLOTKEY',:job,:total)
job total
Employee ELENI ZLOTKEY who works as SA_MAN earns annually total of $151200
PL/SQL procedure successfully completed.
JOB
SA_MAN
TOTAL
151200
VARIABLE
VARIABLE
EXECUTE
PRINT
job VARCHAR2(20)
total NUMBER
Get_Job_Income('GRANT',:job,:total)
job total
Employee KIMBERELY GRANT who works as SA_REP earns annually total of $96600
Employee DOUGLAS GRANT who works as SH_CLERK earns annually total of $31200
PL/SQL procedure successfully completed.
JOB
SH_CLERK
TOTAL
31200
VARIABLE
VARIABLE
EXECUTE
PRINT
job VARCHAR2(20)
total NUMBER
Get_Job_Income('ADAMS',:job,:total)
job total
There is NO such employee ADAMS - Try your input again!
PL/SQL procedure successfully completed.
JOB
TOTAL
2) Write the PACKAGE specification for the Package called Emp_Pack. It will contain Two
Procedures and One Function defined earlier in the Chapter 2 and 3 examples plus the Procedure
from Question 1. Your Package will store following Program Units (in the given order):
Add_Dept, Get_Dept, Get_Job_Income and Get_Mgr. Compile without errors.
3) Write the PACKAGE BODY code for the Package called Emp_Pack.
Compile without errors.
4) Remove Procedure Get_Job_Income created in Question 1) from your schema. Then test
your Package in the similar way you tested this Procedure in Question 1 by providing ‘SMITH’
as your input to the package construct.
Here is the Output.
Employee William SMITH who works as SA_REP earns annually total of $102120
Employee Lindsey SMITH who works as SA_REP earns annually total of $124800
PL/SQL procedure successfully completed.
JOB
SA_MAN
TOTAL
124800
5) Remove Function Get_Income created in Chapter 3 examples earlier. Then test your Package
again by providing ‘SMITH’ as your input to the package construct. What happened?
6) Now, place your Function Get_Income (as the Private or Local one) to the back of the
Package Body. What happened when you compile the Body?
7) Use FORWARD DECLARATION method to fix the Error received in Question 6).
Then test your Package again by providing ‘SMITH’ as your input to the package construct.
Was it successful?
ANSWERS
1)
CREATE OR REPLACE PROCEDURE Get_Job_Income (
p_lname
IN
EMPLOYEES.LAST_NAME%TYPE,
p_job
OUT EMPLOYEES.JOB_ID%TYPE,
p_total
OUT EMPLOYEES.SALARY%TYPE) IS
CURSOR c1 IS
SELECT employee_id, first_name, job_id
FROM employees
WHERE UPPER(last_name) = p_lname;
emp_rec
c1%ROWTYPE;
BEGIN
OPEN c1;
FETCH c1 INTO emp_rec;
IF c1%ROWCOUNT = 0 THEN
DBMS_OUTPUT.PUT_LINE('There is NO such employee ' || p_lname || ' - Try your input
again!');
p_job := NULL;
p_total := NULL;
END IF;
CLOSE c1;
FOR ind IN c1 LOOP
p_total := get_income(ind.employee_id);
p_job := ind.job_id;
DBMS_OUTPUT.PUT_LINE('Employee ' || ind.first_name || ' ' || p_lname || ' who works as '
|| p_job || ' earns annually total of $' || p_total);
END LOOP;
END get_job_income;
/
2)
CREATE OR REPLACE PACKAGE Emp_Pack IS
PROCEDURE Add_Dept (
deptname departments.department_name %TYPE,
deptloc
departments.location_id%TYPE) ;
PROCEDURE Get_Dept (
deptname OUT departments.department_name %TYPE,
deptloc
OUT departments.location_id%TYPE) ;
PROCEDURE Get_Job_Income (
p_lname
IN
EMPLOYEES.LAST_NAME%TYPE,
p_job
OUT EMPLOYEES.JOB_ID%TYPE,
p_total
OUT EMPLOYEES.SALARY%TYPE) ;
FUNCTION Get_Mgr (
dept#
IN
DEPARTMENTS.DEPARTMENT_ID%TYPE)
RETURN NUMBER ;
END emp_pack;
/
3)
CREATE OR REPLACE PACKAGE BODY Emp_Pack IS
PROCEDURE Add_Dept (
deptname departments.department_name %TYPE,
deptloc
departments.location_id%TYPE) IS
error_code
NUMBER;
error_msg
VARCHAR2(255);
BEGIN
INSERT INTO mydept VALUES
(DEPARTMENTS_SEQ.NEXTVAL, DEPTNAME, NULL, DEPTLOC);
EXCEPTION
WHEN OTHERS THEN
Rollback;
error_code := SQLCODE;
error_msg := SQLERRM;
DBMS_OUTPUT.PUT_LINE('Error # is : ' || error_code);
DBMS_OUTPUT.PUT_LINE('Error Message is : ' || error_msg);
END add_dept;
PROCEDURE Get_Dept (
deptname OUT departments.department_name %TYPE,
deptloc
OUT departments.location_id%TYPE) IS
BEGIN
SELECT department_name, location_id
INTO
deptname, deptloc
FROM
mydept
WHERE department_id = (SELECT MAX(department_id)
END
FROM
mydept);
get_dept;
PROCEDURE Get_Job_Income (
p_lname
IN
EMPLOYEES.LAST_NAME%TYPE,
p_job
OUT EMPLOYEES.JOB_ID%TYPE,
p_total
OUT EMPLOYEES.SALARY%TYPE) IS
CURSOR c1 IS
SELECT employee_id, first_name, job_id
FROM employees
WHERE UPPER(last_name) = p_lname;
emp_rec
c1%ROWTYPE;
BEGIN
OPEN c1;
FETCH c1 INTO emp_rec;
IF c1%ROWCOUNT = 0 THEN
DBMS_OUTPUT.PUT_LINE('There is NO such employee ' || p_lname || ' - Try your input
again!');
p_job := NULL;
p_total := NULL;
END IF;
CLOSE c1;
FOR ind IN c1 LOOP
p_total := get_income(ind.employee_id);
p_job := ind.job_id;
DBMS_OUTPUT.PUT_LINE('Employee ' || ind.first_name || ' ' || p_lname || ' who works as '
|| p_job || ' earns annually total of $' || p_total);
END LOOP;
END get_job_income;
FUNCTION Get_Mgr (
dept#
IN
DEPARTMENTS.DEPARTMENT_ID%TYPE)
RETURN NUMBER IS
mgr# DEPARTMENTS.MANAGER_ID%TYPE;
e_mgr
EXCEPTION;
BEGIN
SELECT manager_id INTO mgr#
FROM
departments
WHERE
department_id = dept#;
IF mgr# IS NULL THEN
RAISE e_mgr;
END IF;
RETURN mgr#;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN -1;
WHEN e_mgr THEN
RETURN 0;
END get_mgr;
END emp_pack;
/
4)
DROP PROCEDURE Get_Job_Income
VARIABLE job VARCHAR2(20)
VARIABLE total
NUMBER
EXECUTE
Emp_pack.Get_Job_Income('SMITH',:job,:total)
PRINT
job total
Even without stand alone Procedure in your schema, you could still run it as a part of the
Package.
5)
DROP FUNCTION Get_Income
VARIABLE job VARCHAR2(20)
VARIABLE total
NUMBER
EXECUTE
Emp_pack.Get_Job_Income('SMITH',:job,:total)
PRINT
job total
BEGIN Emp_pack.Get_Job_Income('SMITH',:job,:total); END;
*
ERROR at line 1:
ORA-04063: package body "DBS501_093A40.EMP_PACK" has errors
ORA-06508: PL/SQL: could not find program unit being called:
"DBS501_093A40.EMP_PACK"
Here, without stand alone Function in your schema, you can NOT run your Procedure as a
part of the Package, because it calls for the Function that is NOT part of the same Package.
6)
… the code above in the Body
END get_mgr;
FUNCTION Get_Income (
emp#
IN
EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN NUMBER IS
tot_income EMPLOYEES.SALARY%TYPE;
e_tot
EXCEPTION;
BEGIN
SELECT 12*(NVL(salary,0)*(1+NVL(commission_pct,0))) INTO tot_income
FROM
employees
WHERE
employee_id = emp#;
IF tot_income IS NULL THEN
RAISE e_tot;
END IF;
RETURN tot_income;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN -1;
WHEN e_tot THEN
RETURN 0;
END get_income;
END emp_pack;
 Compiled with errors
Show Errors
Errors for PACKAGE BODY EMP_PACK:
LINE/COL
ERROR
50/8
PL/SQL: Statement ignored
50/19
PLS-00313: 'GET_INCOME' not declared in this scope
Here, the Procedure Get_Job_Income is defined BEFORE the Function that calls for -Get_Income and can NOT be complied without errors.. You may place your Function up
front (as the first Program Unit) OR use the Forward Declaration Method
7) Forward Declaration of the Function Get_Income:
Place just the DECLARATION of the Function (without the code) as the FIRST
construct in the Package Body.
CREATE OR REPLACE PACKAGE BODY Emp_Pack IS
FUNCTION get_income (
emp#
IN
EMPLOYEES.EMPLOYEE_ID%TYPE)
RETURN NUMBER;
PROCEDURE Add_Dept (
… the code below in the Body
VARIABLE job VARCHAR2(20)
VARIABLE total
NUMBER
EXECUTE
Emp_pack.Get_Job_Income('SMITH',:job,:total)
PRINT
job total
 It is SUCCESS as shown below
Employee William SMITH who works as SA_REP earns annually total of $102120
Employee Lindsey SMITH who works as SA_REP earns annually total of $124800
PL/SQL procedure su
Download