Practice PLSQL
Practice PLSQL
2. Using Procedure Builder, add a new department to the DEPT table. Verify
the addition and then ROLLBACK;
Assuming you still have Procedure Builder running and are still
logged on, Expand (click +) the Database Objects node in the
Object Navigator.
Find your schema and expand that node.
Notice the Stored Program Units node.
Click the MY_LOOP procedure in the Program Units node and
drag it to the Stored Program Units node.
Delete the client side MY_LOOP procedure.
Notice the * beside your remaining server-side MY_LOOP. It
did not recompile successfully on the server!
Open the Stored Program Unit editor (by double-clicking on the
icon. Notice the error.
Change TEXT_IO to DBMS_OUTPUT and recompile.
SET SERVEROUTPUT ON
CREATE OR REPLACE PROCEDURE hello_world
IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello World!');
END;
/
Procedure created.
SQL> EXEC hello_world;
Hello World!
PL/SQL procedure successfully completed.
SQL> DROP PROCEDURE hello_world;
Procedure dropped.
3. 2. Create a procedure called ADD_PROD to insert a new product into the
PRODUCT table. The procedure receives a product number and a product
description. If a product with that product number exists, display a
meaningful message on the screen and then generate a server error (hint:
Use RAISE_APPLICATION_ERROR to generate the server error).
Procedure created.
4. 3. Create a procedure called DEL_PROD to delete a product from the
PRODUCT table given a product IDif the product does not exist. Display a
message and then generate a server error.
Test your new procedure with the following statements.
SQL> EXEC del_prod(1);
PL/SQL procedure successfully completed.
SQL> EXEC del_prod(1);
1 does not exist!
BEGIN del_prod(1); END;
*
ERROR at line
ORA-20203: No
ORA-06512: at
ORA-06512: at
1:
products deleted.
"OLN.DEL_PROD", line 9
line 1
18
19
20
21
RAISE_APPLICATION_ERROR
(-20001,'Bad employee number');
END query_emp;
/
Procedure created.
This completes the practice.
Oracle Corporation, 2002
ORDID
---------610
610
610
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DESCRIP
QTY
------------------------------ ---------ACE TENNIS RACKET I
1
ACE TENNIS BALLS-3 PACK
3
ACE TENNIS NET
1
Function created.
7. 2. Create a function called get_sal that returns the salary of an
employee given the employee number. If no employee number is given, it
will return the summation of the salaries from the EMP table. If an invalid
employee number was given, it will return NULL.
Test your function with the following statements.
SQL> VAR TOTAL_SAL NUMBER
21
22
END get_sal;
/
Function created.
Instructions
8. 1. You have created several stand-alone procedures and a function, and
you are now convinced that you would achieve better performance if you
put them into a package. Create a package (PROD_PACK) that has the
ADD_PROD, UPD_PROD, DEL_PROD procedures and the Q_PROD function.
Make the Q_PROD function rivate and, for now, declare that function first
within the body. (You get a compile error if you dont.)
Test your package with the following statements.
SQL> SET SERVEROUTPUT ON
SQL> EXEC prod_pack.add_prod(1,'Orange Slice');
PL/SQL procedure successfully completed.
1:
products deleted.
"OLN.PROD_PACK", line 67
line 1
DBMS_OUTPUT.PUT_LINE
('Product ' || i_prodid ||
' already exists!');
RAISE_APPLICATION_ERROR
(-20202,'No products updated.');
ELSE
DBMS_OUTPUT.PUT_LINE
(i_prodid || ' updated to ' || q_prod(i_prodid));
END IF;
END upd_prod;
PROCEDURE del_prod
(i_prodid IN product.prodid%TYPE)
IS
BEGIN
DELETE FROM product
WHERE prodid = i_prodid;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE
(i_prodid || ' does not exist!');
RAISE_APPLICATION_ERROR
(-20203,'No products deleted.');
END IF;
END DEL_PROD;
FUNCTION q_prod
(v_prodid IN product.prodid%TYPE)
RETURN VARCHAR2
IS
v_descrip product.descrip%TYPE;
BEGIN
SELECT descrip
INTO
v_descrip
FROM
product
WHERE
prodid = v_prodid;
RETURN (v_descrip);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN 'Invalid Product Number';
END q_prod;
SQL>
2
3
4
5
6
7
8
9
10
11
12
(i_prodid
IN product.prodid%TYPE,
i_descrip IN product.descrip%TYPE);
PROCEDURE del_prod
(i_prodid IN product.prodid%TYPE);
END prod_pack;
/
Package created.
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
(i_prodid || ' was ' || q_prod(i_prodid));
43
UPDATE product
44
SET
descrip = i_descrip
45
WHERE prodid = i_prodid;
46
IF SQL%NOTFOUND THEN
47
DBMS_OUTPUT.PUT_LINE
48
('Product ' || i_prodid ||
49
' already exists!');
50
RAISE_APPLICATION_ERROR
51
(-20202,'No products updated.');
52
ELSE
53
DBMS_OUTPUT.PUT_LINE
54
(i_prodid || ' updated to ' ||
q_prod(i_prodid));
55
END IF;
56 END upd_prod;
57 -58 PROCEDURE del_prod
59
(i_prodid IN product.prodid%TYPE)
60 IS
61 BEGIN
62
DELETE FROM product
63
WHERE prodid = i_prodid;
64
IF SQL%NOTFOUND THEN
65
DBMS_OUTPUT.PUT_LINE
66
(i_prodid || ' does not exist!');
67
RAISE_APPLICATION_ERROR
68
(-20203,'No products deleted.');
69
END IF;
70 END DEL_PROD;
71 -72 END prod_pack;
73 /
Package body created.
Create a package called EMP_PACK. For now, the package contains one
public function called get_dept_sal. The function, given a department
number, will return the total salaries of the employees (EMP table) in that
department. Test your packaged function with the following statement.
SQL> VARIABLE DEPT_SAL NUMBER
SQL> EXECUTE :dept_sal := emp_pack.get_dept_sal(10)
PL/SQL procedure successfully completed.
SQL> PRINT dept_sal
DEPT_SAL
---------8750
SQL>
2
3
4
5
6
7
Package created.
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
4
5
6
7
8
AND
AND
job
= 'MANAGER'
deptno = (SELECT deptno
FROM
emp
WHERE empno = 7788) -- EMPLOYEE
?
---TRUE
Test your package with the following block.
SQL> BEGIN
2
IF emp_pack.VALID_DEPTNO(10) THEN
3
DBMS_OUTPUT.PUT_LINE('10 IS GOOD!');
4
END IF;
5
IF emp_pack.VALID_DEPTNO(99) = FALSE THEN
6
DBMS_OUTPUT.PUT_LINE('99 IS NO GOOD!');
7
END IF;
8
IF emp_pack.chk_mgr(7566,7788) THEN
9
DBMS_OUTPUT.PUT_LINE('7566,7788 IS GOOD!');
10
END IF;
11
IF emp_pack.chk_mgr(7788,7566) = FALSE THEN
12
DBMS_OUTPUT.PUT_LINE('7788,7566 IS NO
GOOD!');
13
END IF;
14 END;
15 /
10 IS GOOD!
99 IS NO GOOD!
7566,7788 IS GOOD!
7788,7566 IS NO GOOD!
PL/SQL procedure successfully completed.
SQL>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-END emp_pack;
/
Package created.
CREATE OR REPLACE PACKAGE BODY emp_pack
IS
-FUNCTION get_dept_sal
(i_deptno
emp.deptno%TYPE)
RETURN NUMBER
IS
v_dept_sal
emp.sal%TYPE;
BEGIN
SELECT SUM(sal)
INTO
v_dept_sal
FROM
emp
WHERE deptno = i_deptno;
RETURN v_dept_sal;
END get_dept_sal;
-FUNCTION valid_deptno
(i_deptno
emp.deptno%TYPE)
RETURN BOOLEAN
IS
v_result
VARCHAR2(1);
BEGIN
SELECT 'x'
INTO
v_result
FROM
dept
WHERE deptno = i_deptno;
-- IF YOU MADE IT THIS FAR, THE DEPTNO EXISTS!
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- DEPTNO DOESN'T
EXIST!
RETURN FALSE;
WHEN OTHERS THEN
RETURN NULL;
END valid_deptno;
-FUNCTION chk_mgr
(i_mgr
emp.mgr%TYPE,
i_empno
emp.empno%TYPE)
RETURN BOOLEAN
IS
v_result
VARCHAR2(1);
BEGIN
SELECT 'x'
INTO
FROM
WHERE
AND
AND
v_result
emp
empno = i_mgr
job
= 'MANAGER'
deptno = (SELECT deptno
FROM
emp
WHERE empno = i_empno);
-- if you made it this far, the combo is good!
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN FALSE;
WHEN OTHERS
THEN
RETURN NULL;
END chk_mgr;
END emp_pack;
/
10. 3. It is now time to finalize your package. You need one more procedure
added to your package that will insert new employees. The procedure
NEW_EMP:
a) a) Only requires an employee number and a name. The rest could be
defaults. These defaults are
Job
DEFAULT 'SALESMAN'
Mgr
DEFAULT 7839
Sal
DEFAULT 1000
Comm
DEFAULT 0
Deptno
DEFAULT 30
Hiredate can be assumed to be midnight, today. (Hint: This can be
built programmatically into your insert statement)
b) b) Only allows the insert to take place if the department number is
valid (VALID_DEPTNO).
c) c) After the insert, determines whether the Manager and Employee
number is a valid combination. If the combination is bad, rollback to a
point before the insert. (Hint: SAVEPOINT)
d) d) Currently, the order of your program units is important so ensure
that NEW_EMP is the last unit defined in your package body.
Test your newly improved package with the following statements.
SQL> EXEC emp_pack.new_emp(1,'GRANT')
PL/SQL procedure successfully completed.
19
i_ename
20
i_job
'SALESMAN',
21
i_mgr
22
i_sal
23
i_comm
24
i_deptno
25
26 END emp_pack;
27 /
emp.ename%TYPE,
emp.job%TYPE
DEFAULT
emp.mgr%TYPE
emp.sal%TYPE
emp.comm%TYPE
emp.deptno%TYPE
DEFAULT
DEFAULT
DEFAULT
DEFAULT
7698,
1000,
0,
30);
Package created.
SQL>
SQL> CREATE OR REPLACE PACKAGE BODY emp_pack
2 IS
3 -4
FUNCTION get_dept_sal
5
(i_deptno
emp.deptno%TYPE)
6
RETURN NUMBER
7
IS
8
v_dept_sal
emp.sal%TYPE;
9
BEGIN
10
SELECT SUM(sal)
11
INTO
v_dept_sal
12
FROM
emp
13
WHERE deptno = i_deptno;
14
RETURN v_dept_sal;
15
END get_dept_sal;
16 -17
FUNCTION valid_deptno
18
(i_deptno
emp.deptno%TYPE)
19
RETURN BOOLEAN
20
IS
21
v_result
VARCHAR2(1);
22
BEGIN
23
SELECT 'x'
24
INTO
v_result
25
FROM
dept
26
WHERE deptno = i_deptno;
27
-- IF YOU MADE IT THIS FAR, THE DEPTNO
EXISTS!
28
RETURN TRUE;
29
EXCEPTION
30
WHEN NO_DATA_FOUND THEN -- DEPTNO DOESN'T
EXIST!
31
RETURN FALSE;
32
WHEN OTHERS THEN
33
RETURN NULL;
34
END valid_deptno;
35 -36
FUNCTION chk_mgr
37
(i_mgr
emp.mgr%TYPE,
38
i_empno
emp.empno%TYPE)
39
RETURN BOOLEAN
40
IS
41
v_result
VARCHAR2(1);
42
BEGIN
43
SELECT 'x'
44
INTO
v_result
45
FROM
emp
46
WHERE empno = i_mgr
47
AND
job
= 'MANAGER'
48
AND
deptno = (SELECT deptno
49
FROM
emp
50
WHERE empno = i_empno);
51
-- if you made it this far, the combo is
good!
52
RETURN TRUE;
53
EXCEPTION
54
WHEN NO_DATA_FOUND THEN
55
RETURN FALSE;
56
WHEN OTHERS
THEN
57
RETURN NULL;
58
END chk_mgr;
59
60
PROCEDURE new_emp
61
(i_empno
emp.empno%TYPE,
62
i_ename
emp.ename%TYPE,
63
i_job
emp.job%TYPE
DEFAULT
'SALESMAN',
64
i_mgr
emp.mgr%TYPE
DEFAULT 7698,
65
i_sal
emp.sal%TYPE
DEFAULT 1000,
66
i_comm
emp.comm%TYPE
DEFAULT 0,
67
i_deptno emp.deptno%TYPE DEFAULT 30)
68
IS
69
BEGIN
70
IF valid_deptno(i_deptno) THEN
71
SAVEPOINT before_insert;
72
INSERT INTO emp
73
VALUES (i_empno, i_ename, i_job, i_mgr,
74
TRUNC (SYSDATE), i_sal, i_comm,
i_deptno);
75
ELSE
76
RAISE_APPLICATION_ERROR (-20205,
77
'Invalid department number. Try
again.');
78
END IF;
79
IF chk_mgr(I_mgr,I_empno) = TRUE THEN
80
NULL;
81
82
83
84
85
86
87
88
89
90
ELSE
ROLLBACK TO SAVEPOINT before_insert;
RAISE_APPLICATION_ERROR (-20206,
'Invalid Manager for this employee!');
END IF;
END new_emp;
END emp_pack;
/
Instructions
11. 1. It is now time to enhance the EMP_PACK package that you created in
the previous practice. (If you have lost it, the code is given at the end of
this question). You decided that you would like the function
get_dept_sal to return the total salary of the whole table if it is not
passed a department number. Although you could use defaults for this,
you decide you would like to overload the function.
'SALESMAN',
7698,
1000,
0,
30);
/
CREATE OR REPLACE PACKAGE BODY emp_pack
IS
-FUNCTION get_dept_sal
(i_deptno
emp.deptno%TYPE)
RETURN NUMBER
IS
v_dept_sal
emp.sal%TYPE;
BEGIN
SELECT SUM(sal)
INTO
v_dept_sal
FROM
emp
WHERE deptno = i_deptno;
RETURN v_dept_sal;
END get_dept_sal;
-FUNCTION valid_deptno
(i_deptno
emp.deptno%TYPE)
RETURN BOOLEAN
IS
v_result
VARCHAR2(1);
BEGIN
SELECT 'x'
INTO
v_result
FROM
dept
WHERE deptno = i_deptno;
-- IF YOU MADE IT THIS FAR, THE DEPTNO EXISTS!
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- DEPTNO DOESN'T EXIST!
RETURN FALSE;
WHEN OTHERS THEN
RETURN NULL;
END valid_deptno;
-FUNCTION chk_mgr
(i_mgr
emp.mgr%TYPE,
i_empno
emp.empno%TYPE)
RETURN BOOLEAN
IS
v_result
VARCHAR2(1);
BEGIN
SELECT 'x'
INTO
v_result
FROM
emp
WHERE empno = i_mgr
AND
job
= 'MANAGER'
AND
deptno = (SELECT deptno
FROM
emp
*
ERROR at line 1:
ORA-20205: Invalid department number. Try again.
ORA-06512: at "OLN.EMP_PACK", line 97
ORA-06512: at line 1
SQL> EXEC emp_pack.new_emp(3,'ROBERT', i_deptno => 20)
BEGIN emp_pack.new_emp(3,'ROBERT', i_deptno => 20);
END;
*
ERROR at line 1:
ORA-20206: Invalid Manager for this employee!
ORA-06512: at "OLN.EMP_PACK", line 104
ORA-06512: at line 1
CREATE OR REPLACE PACKAGE emp_pack
IS
-FUNCTION get_dept_sal
(i_deptno
emp.deptno%TYPE)
RETURN NUMBER;
-FUNCTION get_dept_sal
RETURN NUMBER;
-PROCEDURE new_emp
(i_empno
emp.empno%TYPE,
i_ename
emp.ename%TYPE,
i_job
emp.job%TYPE
i_mgr
emp.mgr%TYPE
i_sal
emp.sal%TYPE
i_comm
emp.comm%TYPE
i_deptno emp.deptno%TYPE
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
END emp_pack;
/
CREATE OR REPLACE PACKAGE BODY emp_pack
IS
--FORWARD DECLARATIONS-------------FUNCTION valid_deptno
(i_deptno
emp.deptno%TYPE)
RETURN BOOLEAN;
-FUNCTION chk_mgr
(i_mgr
emp.mgr%TYPE,
i_empno
emp.empno%TYPE)
RETURN BOOLEAN;
'SALESMAN',
7698,
1000,
0,
30);
Here is the final state of the package after all these questions.
CREATE OR REPLACE PACKAGE emp_pack
IS
-FUNCTION get_dept_sal
(i_deptno
emp.deptno%TYPE)
RETURN NUMBER;
-FUNCTION get_dept_sal
RETURN NUMBER;
-PROCEDURE new_emp
(i_empno
emp.empno%TYPE,
i_ename
emp.ename%TYPE,
i_job
emp.job%TYPE
i_mgr
emp.mgr%TYPE
i_sal
emp.sal%TYPE
i_comm
emp.comm%TYPE
i_deptno emp.deptno%TYPE
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
'SALESMAN',
7698,
1000,
0,
30);
FUNCTION check_dept_job
(i_job
emp.job%TYPE,
i_deptno emp.deptno%TYPE)
RETURN BOOLEAN;
END emp_pack;
/
CREATE OR REPLACE PACKAGE BODY emp_pack
IS
-- CURSOR and INDEX-BY table used in One-Time only Proc
CURSOR dept_job_c IS
SELECT DISTINCT deptno, job
FROM
emp;
TYPE dept_job_table_type IS TABLE OF dept_job_c%ROWTYPE
INDEX BY BINARY_INTEGER;
dept_job_table
dept_job_table_type;
counter
PLS_INTEGER := 0;
--FORWARD DECLARATIONS-------------FUNCTION valid_deptno
(i_deptno
emp.deptno%TYPE)
RETURN BOOLEAN;
-FUNCTION chk_mgr
(i_mgr
emp.mgr%TYPE,
i_empno
emp.empno%TYPE)
RETURN BOOLEAN;
--FORWARD DECLARATIONS END---------FUNCTION get_dept_sal
(i_deptno
emp.deptno%TYPE)
RETURN NUMBER
IS
v_dept_sal
emp.sal%TYPE;
BEGIN
SELECT SUM(sal)
INTO
v_dept_sal
FROM
emp
WHERE deptno = i_deptno;
RETURN v_dept_sal;
END get_dept_sal;
-FUNCTION get_dept_sal
RETURN NUMBER
IS
v_dept_sal
emp.sal%TYPE;
BEGIN
SELECT SUM(sal)
INTO
v_dept_sal
FROM
emp;
RETURN v_dept_sal;
END get_dept_sal;
-FUNCTION valid_deptno
(i_deptno
emp.deptno%TYPE)
RETURN BOOLEAN
IS
v_result
VARCHAR2(1);
BEGIN
SELECT 'x'
INTO
v_result
FROM
dept
WHERE deptno = i_deptno;
-- IF YOU MADE IT THIS FAR, THE DEPTNO EXISTS!
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- DEPTNO DOESN'T EXIST!
RETURN FALSE;
WHEN OTHERS THEN
RETURN NULL;
END valid_deptno;
-FUNCTION chk_mgr
(i_mgr
i_empno
emp.mgr%TYPE,
emp.empno%TYPE)
RETURN BOOLEAN
IS
v_result
VARCHAR2(1);
BEGIN
SELECT 'x'
INTO
v_result
FROM
emp
WHERE empno = i_mgr
AND
job
= 'MANAGER'
AND
deptno = (SELECT deptno
FROM
emp
WHERE empno = i_empno);
-- if you made it this far, the combo is good!
RETURN TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN FALSE;
WHEN OTHERS
THEN
RETURN NULL;
END chk_mgr;
PROCEDURE new_emp
(i_empno
emp.empno%TYPE,
i_ename
emp.ename%TYPE,
i_job
emp.job%TYPE
DEFAULT 'SALESMAN',
i_mgr
emp.mgr%TYPE
DEFAULT 7698,
i_sal
emp.sal%TYPE
DEFAULT 1000,
i_comm
emp.comm%TYPE
DEFAULT 0,
i_deptno emp.deptno%TYPE DEFAULT 30)
IS
BEGIN
IF valid_deptno(i_deptno) THEN
SAVEPOINT before_insert;
INSERT INTO emp
VALUES (i_empno, i_ename, i_job, i_mgr,
TRUNC (SYSDATE), i_sal, i_comm, i_deptno);
ELSE
RAISE_APPLICATION_ERROR (-20205,
'Invalid department number. Try again.');
END IF;
IF chk_mgr(I_mgr,I_empno) = TRUE THEN
NULL;
ELSE
ROLLBACK TO SAVEPOINT before_insert;
RAISE_APPLICATION_ERROR (-20206,
'Invalid Manager for this employee!');
END IF;
END new_emp;
FUNCTION check_dept_job
(i_job
emp.job%TYPE,
i_deptno emp.deptno%TYPE)
RETURN BOOLEAN
IS
BEGIN
FOR i IN dept_job_table.FIRST .. dept_job_table.LAST LOOP
IF dept_job_table(i).deptno = i_deptno AND
dept_job_table(i).job
= i_job
THEN
RETURN TRUE;
END IF;
END LOOP;
RETURN FALSE; -- MADE IT THIS FAR ... NEVER GOT A MATCH!
END check_dept_job;
--- Start of one time only procedure to load table.
BEGIN
FOR dept_job_c_rec IN dept_job_c LOOP
counter := counter + 1;
dept_job_table(counter) := dept_job_c_rec;
END LOOP;
END emp_pack;
/
14. 4. Finally, you have decided that you would like to ensure the purity of the
get_dept_sal function inside your emp_pack. You want to ensure that,
at compile time, the compiler checks to ensure that this function does not
access a database or a packaged variable.
(Hint: PRAGMA )
CREATE OR REPLACE PACKAGE emp_pack
IS
-FUNCTION get_dept_sal
(i_deptno
emp.deptno%TYPE)
RETURN NUMBER;
PRAGMA
RESTRICT_REFERENCES(get_dept_sal,WNDS,WNPS,RNPS);
-FUNCTION get_dept_sal
RETURN NUMBER;
PRAGMA
RESTRICT_REFERENCES(get_dept_sal,WNDS,WNPS,RNPS);
-Rest of package specification unchanged
Instructions
Creating a Procedure
1) Create a procedure DROP_TABLE that drops the table specified in the input parameter. Use
the procedures and functions from the supplied DBMS_SQL package.
Test the DROP_TABLE procedure by creating a new table called EMP_DUP as a copy of the
EMP table, then executing the DROP_TABLE procedure to drop the EMP_DUP table.
SQL> CREATE OR REPLACE PROCEDURE drop_table
2
3
(v_table_name IN VARCHAR2)
IS
dyn_cur number;
dyn_err varchar2(255);
BEGIN
dyn_cur := DBMS_SQL.OPEN_CURSOR;
v_table_name,DBMS_SQL.NATIVE);
10
DBMS_SQL.CLOSE_CURSOR(dyn_cur);
11
12
EXCEPTION
WHEN OTHERS THEN dyn_err := sqlerrm;
13
DBMS_SQL.CLOSE_CURSOR(dyn_cur);
14
RAISE_APPLICATION_ERROR(-20600,dyn_err);
15
END drop_table;
16
Procedure created.
SQL> CREATE TABLE emp_dup
2
Table created.
SQL> EXECUTE drop_table('emp_dup')
PL/SQL procedure successfully completed.
SQL> SELECT * FROM emp_dup;
*
ERROR at line 1:
ORA-00942: table or view does not exist
(v_table_name
IS
BEGIN
5
6
IN
VARCHAR2)
7/
Procedure created.
SQL> CREATE TABLE emp_dup
2
Table created.
SQL> EXECUTE drop_table2('emp_dup')
PL/SQL procedure successfully completed.
SQL> SELECT * FROM emp_dup;
*
ERROR at line 1:
Table created.
SQL> VARIABLE JOBNO NUMBER
SQL> EXECUTE DBMS_JOB.SUBMIT(:JOBNO, 'DROP_TABLE2(''EMP_DUP'');', SYSDATE + (5.0/24.0)/60.0)
PL/SQL procedure successfully completed.
SQL> PRINT JOBNO
JOBNO
-------------1
FROM USER_JOBS
JOB
NEXT_DATE
NEXT_SEC
---
----------
-------- ---------------------
30-SEP-2002
05:32:46
WHAT
DROP_TABLE2(EMP_DUP);
IS
BEGIN
IF
THEN
10
11
12
office hours.');
13
END IF;
14 END time_check;
15 /
Procedure created.
b) Create a trigger called secure_ord on the ord table. Fire the trigger
before data is inserted, updated, and deleted. Call your TIME_CHECK
procedure from this trigger.
SQL> CREATE OR REPLACE TRIGGER secure_ord
2
BEGIN
time_check;
END secure_ord;
6 /
Trigger created.
Instructions
Data integrity and referential integrity:
1. Create a trigger to ensure that once an order has been shipped, it can never be
changed.
a) Create a trigger ITEM_ORDER_SHIPPED. The trigger should be fired
before data is inserted, updated or deleted in a row in the ITEM table. When
a row is changed in the ITEM table, check to see if that row exists in the ORD
table. If the SHIPDATE column has a value in the ORD table, fail the trigger.
Add exception handling and give appropriate message if the trigger fails.
SQL> CREATE OR REPLACE TRIGGER item_order_shipped
2
DECLARE
v_ordid
number;
v_shipdate
date;
BEGIN
10
FROM ord
11
12
13
RAISE_APPLICATION_ERROR(-20500,
14
15
16
END IF;
17
EXCEPTION
18
19
20
exist');
END;
21 /
Trigger created.
BEGIN
RAISE_APPLICATION_ERROR(-20550,' Corresponding
allowed.');
9
10
END;
/
Trigger created.
Test the trigger. You can use the following data before and after creating the
triggers.
SQL> UPDATE item
2
SET qty = 20
UPDATE item
*
ERROR at line 1:
ORA-20500: Corresponding order has already been shipped,no changes
allowed.
ORA-06512: at : ORAxx.ITEM_ORDER_SHIPPED, line 19
ORA-04088: error during execution of trigger
ORAxx.ITEM_ORDER_SHIPPED
UPDATE ord
*
ERROR at line 1:
ORA-20550: Corresponding order has already been shipped,no changes
allowed.
ORA-06512: at : ORAxx.ORD_ORDER_SHIPPED, line 2
ORA-04088: error during execution of trigger
ORAxx.ORD_ORDER_SHIPPED
Drop these triggers before proceeding to the next exercise.
SQL> DROP TRIGGER item_order_shipped;
Trigger dropped.
SQL> DROP TRIGGER item_order_shipped;
Trigger dropped.
BEGIN
IF INSERTING THEN
upd_ord(:NEW.ordid, :NEW.itemtot);
10
upd_ord(:OLD.ordid, -:OLD.itemtot);
11
12
END IF;
END;
13
Trigger created.
BEGIN
UPDATE ord
END;
Procedure created.
b) Test the trigger. You can use the following data before and after creating
the triggers.
SQL> SELECT *
2
FROM item
ORDID
ITEMID
PRODID ACTUALPRICE
QTY
ITEMTOT
100861
45
10
450
621
100870
2.8
100
280
SQL> SELECT *
2
FROM ord
-------- ----------
CUSTID SHIPDATE
TOTAL
621 15-MAR-1987 A
100 1-JAN-1987
730
1 row created.
SQL> SELECT *
2
FROM item
ORDID
ITEMID
PRODID ACTUALPRICE
QTY
ITEMTOT
100861
45
10
450
621
100870
2.8
100
280
621
100871
5.6
100
560
SQL> SELECT *
2
FROM ord
-------- ----------
CUSTID SHIPDATE
TOTAL
621 15-MAR-1987 A
100 1-JAN-1987
1290
FROM user_triggers
FROM user_source
ORDER BY line;
TEXT
-----------------------------------------------------------------PROCEDURE time_check
IS
BEGIN
IF (TO_CHAR (SYSDATE, 'HH24:MI') NOT BETWEEN '08:00' AND
'22:00'
'DY') IN ('SUN', 'MON', 'TUE',
'WED', 'THU', 'FRI'))
OR (TO_CHAR (SYSDATE, 'HH24:MI') NOT BETWEEN '08:00' AND
'24:00'
AND TO_CHAR (SYSDATE, 'DY') = 'SAT' )
THEN
RAISE_APPLICATION_ERROR (-20205,
'You may only make changes during normal office hours.');
END IF;
END time_check;
15 rows selected
SQL> CREATE OR REPLACE PROCEDURE time_check
2
IS
BEGIN
4
'22:00'
'WED', 'THU'))
'24:00'
10
THEN
11
12
13
END IF;
14 END time_check;
15 /
Procedure created.
Note: when you work with Procedure Builder you need not to query the data
dictionary for the text of the procedure and the body of the trigger. The trigger
is stored by the table, the procedure youll find in the section Stored Program
Units. You could simply copy the text of the procedure via the menu.
After you have connected to the Procedure Builder with the
username/password and connectstring provided to you, select Database
Objects, select your username, then Stored Program Units. Activate the
program TIME_CHECK. You now could copy the text of the procedure by
using the menu; Program, choose Stored Program Unit Editor. Copy this, go
to SQL*Plus, add the words Create or Replace before the text and save it
as a file. In Procedure Builder you cant save text files.
Note: In order for your trigger to fail, you may need to change
the time to be outside the range of your current time while
performing this exercise.
SQL> insert into ord
2
TYPE
---------------------
--------------------
SECURE_ORD
TRIGGER
STATUS
---------------
-----------------
--------
BONUS
TABLE
VALID
CUSTID
SEQUENCE
VALID
27 rows selected.
d) Create a procedure to dynamically recompile all dependent objects on this procedure. Use
the procedure name as an input parameter. Make use of the ALTER_COMPILE procedure in
the DBMS_DDL package. Execute the procedure you just created.
SQL> CREATE OR REPLACE PROCEDURE compile_obj
(p_obj_name IN VARCHAR2)
IS
CURSOR obj_cur IS
FROM user_dependencies
BEGIN
10
11
END LOOP;
12
END;
13
Procedure created.
SQL> EXECUTE compile_obj('TIME_CHECK')
PL/SQL procedure successfully completed.
e) Check to see if these dependent objects are INVALID.
SQL> SELECT object_name, object_type, status
2 FROM user_objects;
OBJECT_NAME
OBJECT_TYPE
STATUS
---------------
-----------------
--------
BONUS
TABLE
VALID
COMPILE_OBJ
PROCEDURE
VALID
CUSTID
SEQUENCE
VALID
28 rows selected.