Sie sind auf Seite 1von 8

Homework Week #7

PL/SQL Virtual Training


1. First some questions about packages, what they can contain, what they are made up of and how we find
out which ones we have access to in our accounts.

A. Name at least four objects that can be put into a package.

Procedures, Functions, Variables, Cursors, Exceptions, Constants.

B. Name the two components of a package and explain the difference between them.

Specification (or Spec) and Body. The Specification declares the subprograms in the package, while the
Body contains the detailed code of the subprograms.

C. Which of the two components must be created first, and why?

The Specification must be created first. The Body is optional but the Specification is not. Therefore a
Spec can exist without a Body, but a Body cannot exist without a Spec.

D. Write a query against a Data Dictionary view to show you a list of packages you own.

SELECT *
FROM user_objects
WHERE object_type LIKE 'PACK%';

2. Create the specification for the check_emp_pkg which you studied in this lesson. The specification
should declare a constant and two procedures, as follows:

g_max_length_of_service, datatype NUMBER, initialized to 100

chk_hiredate with one input parameter having the same datatype as employees.hire_date

chk_dept_mgr with two input parameters having the same datatypes as employees.employee_id and
employees.manager_id.

CREATE OR REPLACE PACKAGE check_emp_pkg


IS
g_max_length_of_service CONSTANT NUMBER := 100;
PROCEDURE chk_hiredate
(p_date IN employees.hire_date%TYPE);
PROCEDURE chk_dept_mgr
(p_empid IN employees.employee_id%TYPE,
p_mgr IN departments.manager_id%TYPE);
END check_emp_pkg;
3. Create the package body for check_emp_pkg. Remember that the names and parameters of the
procedures in the body must be identical to those in the specification, or the body will not compile.

The code for chk_hiredate should RAISE_APPLICATION_ERROR if the employee was hired more than
100 years ago (hint: use MONTHS_BETWEEN, comparing with g_max_length_of_service * 12).

The second procedure, chk_dept_mgr, accepts two input parameters: an employee_id and a manager_id. The
code should find the manager of the employee’s department and check whether this manager has the same
manager_id as the second parameter. If the manager_id is the same, display a suitable “success” message; if
they are different, raise an application error. Include an exception handler for NO_DATA_FOUND.
The following sample data from the employees and departments tables may help you:

Departments:

Employees:

Passing parameters (174,149) would be


successful, while (174,176) would raise
an error.

CREATE OR REPLACE PACKAGE BODY check_emp_pkg IS


PROCEDURE chk_hiredate
(p_date IN employees.hire_date%TYPE)
IS BEGIN
IF MONTHS_BETWEEN(SYSDATE, p_date) >
g_max_length_of_service * 12 THEN
RAISE_APPLICATION_ERROR(-20201,'Hiredate Too Old');
END IF;
END chk_hiredate;
PROCEDURE chk_dept_mgr
(p_empid IN employees.employee_id%TYPE,
p_mgr IN departments.manager_id%TYPE)
IS
v_dept_id employees.department_id%TYPE;
v_mgr_id departments.manager_id%TYPE;
BEGIN
SELECT department_id INTO v_dept_id
FROM employees
WHERE employee_id = p_empid;
SELECT manager_id INTO v_mgr_id
FROM departments
WHERE department_id = v_dept_id;
IF v_mgr_id = p_mgr THEN
DBMS_OUTPUT.PUT_LINE
('This manager is valid for this employee');
ELSE
RAISE_APPLICATION_ERROR(-20202,
'This manager is not valid for this employee');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20203,
'This employee or department does not exist');
END chk_dept_mgr;
END check_emp_pkg;
4. Procedure chk_hiredate:
A. Test the chk_hiredate procedure using input value 17-Jan-87 (it should succeed).

BEGIN
check_emp_pkg.chk_hiredate('17-jan-87');
END;

B. Test the chk_dept_mgr procedure twice using input values (174,149) and (174,176). The first should
succeed while the second should fail.

BEGIN
check_emp_pkg.chk_dept_mgr(174, 149);
END;
BEGIN
check_emp_pkg.chk_dept_mgr(174, 176);
END;

5. Now you want to modify the package so that the chk_dept_mgr procedure displays a different error
message if the two manager_ids are different. What do you need to recreate: the Specification, the Body,
or both? Make the change and test it again, using (174,176) as before.

The Body must be edited and recreated, but not the Specification.

6. Create a package called overload. The package should contain three procedures all called what_am_i.
The first procedure should accept a VARCHAR2 as an IN parameter, the second a NUMBER and the
third a DATE. Each procedure should display a simple message to show which datatype was passed to it.
For example, the first procedure could display “Here I am a Varchar2”. Save your work for later.
When you are done, describe the package.
7.
CREATE OR REPLACE PACKAGE overload
IS
PROCEDURE what_am_i(p_in VARCHAR2);
PROCEDURE what_am_i(p_in NUMBER);
PROCEDURE what_am_i(p_in DATE);
END overload;

CREATE OR REPLACE PACKAGE BODY overload


AS
PROCEDURE what_am_i(p_in VARCHAR2)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Here I am a Varchar2');
END what_am_i;
PROCEDURE what_am_i(p_in NUMBER)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Here I am a Number');
END what_am_i;
PROCEDURE what_am_i(p_in DATE)
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Here I am a Date');
END what_am_i;
END overload;

8. Test the overload package by calling it and passing in a character string, a number and a date respectively.
You should see the different messages returned. – Note: you must use the TO_DATE function to pass a
value in as a date.

9. Suppose you write a packaged function that returns a BOOLEAN value of TRUE or FALSE. Does the
BOOLEAN limit the possible places from which you can call the packaged function?

Yes, you can’t use the function a part of a SQL statement because the datatype is unknown.
Use inside a PL?SQL statement.

10. What does the UTL_FILE package allow you to do?

Allows you to read/write to text files on external disk.

11. The Database Administrator has executed the following statement to create a directory object:

CREATE DIRECTORY emps_dir AS ‘/u01/employee_data’;

You want to create a text report of all employees’ last names and salaries. The report must have an
operating system path and file name of ‘/u01/employee_data/salaries.txt’, and must list the
employees in ascending salary order.

A. The following procedure code contains several deliberate errors. Try to create the procedure
using this code, and note the error messages.

CREATE OR REPLACE PROCEDURE list_sals IS


v_file UTL_FILE.FILE_TYPE;
CURSOR empc IS
SELECT last_name, salary FROM employees
ORDER BY salary;
BEGIN
UTL_FILE.PUT_LINE(v_file, ' *** START OF REPORT ***');
v_file:= UTL_FILE.FOPEN ('EMPS_DIR', salaries.txt, 'w');
FOR emp_rec IN empc LOOP
UTL_FILE.PUT_LINE (v_file, emp_rec.last_name ||
' earns: ' || emp_rec.salary);
END LOOP;
UTL_FILE.PUT_LINE('*** END OF REPORT ***');
UTL_FILE.FCLOSE (v_file);
EXCEPTION
WHEN UTL_FILE.INVALID_FILE_HANDLE THEN
RAISE_APPLICATION_ERROR(-20001,'Invalid File.');
WHEN UTL_FILE.WRITE_ERROR THEN
RAISE_APPLICATION_ERROR (-20002,
'Unable to write to file');
END list_sals;

The call to UTL_FILE.PUT_LINE is made before the file is opened


In UTL_FILE.FOPEN the text filename must be in quotes
The last call to UTL_FILE.PUT_LINE missing the file handle
The exception INVALID_FILEHANDLE is misspelled.

Modify the code to correct the errors and re-create the procedure. Do not execute the procedure.

CREATE OR REPLACE PROCEDURE list_sals IS


v_file UTL_FILE.FILE_TYPE;
CURSOR empc IS
SELECT last_name, salary FROM employees
ORDER BY salary;
BEGIN
v_file:= UTL_FILE.FOPEN ('EMPS_DIR', 'salaries.txt', 'w');
UTL_FILE.PUT_LINE(v_file, ' *** START OF REPORT ***');
FOR emp_rec IN empc LOOP
UTL_FILE.PUT_LINE (v_file, emp_rec.last_name || ' earns: ' ||
emp_rec.salary);
END LOOP;
UTL_FILE.PUT_LINE(v_file, '*** END OF REPORT ***');
UTL_FILE.FCLOSE (v_file);
EXCEPTION
WHEN UTL_FILE.INVALID_FILEHANDLE THEN
RAISE_APPLICATION_ERROR(-20001,'Invalid File.');
WHEN UTL_FILE.WRITE_ERROR THEN
RAISE_APPLICATION_ERROR (-20002,
'Unable to write to file');
END list_sals;
12. List three reasons why using the EXECUTE IMMEDIATE command is preferable to using the
DBMS_SQL package.

 Easier to understand and therefore easier to avoid errors.


 Requires less coding: a single call to EXECUTE IMMEDIATE does it all.
 Often faster execution than DBMS_SQL.

13. The departments and employees tables have two columns in common: department_id and manager_id.
Create a procedure that uses a single EXECUTE IMMEDIATE call to select and display a department_id
from either table, where the manager_id is 205. The procedure should accept the table name as an input
parameter and display the department_id from that table. Remember to handle any possible exceptions
that might be raised, because we are selecting into a single variable, not using a cursor in this case.

CREATE OR REPLACE PROCEDURE disp_data(p_table_name VARCHAR2) IS


v_dept_id NUMBER(4);
BEGIN
EXECUTE IMMEDIATE 'SELECT department_id FROM '
|| p_table_name
|| ' WHERE manager_id = 205'
INTO v_dept_id;
DBMS_OUTPUT.PUT_LINE('The department ID is: '|| v_dept_id);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('There are no rows for this table
/ manager ID combination');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('There are too many rows for this table
/ manager ID combination.');
END;

14. Create and execute an anonymous block containing the BULK COLLECT and RETURNING clause.
Use the Employee table.

DROP TABLE emp_temp;


CREATE TABLE emp_temp AS SELECT * FROM employees;
DECLARE
TYPE NumList IS TABLE OF employees.employee_id%TYPE;
enums NumList;
TYPE NameList IS TABLE OF employees.last_name%TYPE;
names NameList;
BEGIN
DELETE FROM emp_temp
WHERE department_id = 30
RETURNING employee_id, last_name
BULK COLLECT INTO enums, names;
DBMS_OUTPUT.PUT_LINE ('Deleted ' || SQL%ROWCOUNT || ' rows:');
FOR i IN enums.FIRST .. enums.LAST
LOOP
DBMS_OUTPUT.PUT_LINE ('Employee #' || enums(i) || ': ' || names(i));
END LOOP;
END;

Das könnte Ihnen auch gefallen