Sie sind auf Seite 1von 12

www.oracle.

com/academy

Certification Preparation PL/SQL


Code Samples and Questions

Part 1 of this document contains two PL/SQL code samples and questions. Answer the
questions that follow each of the PL/SQL code samples. Attempt to spend no more than 2
minutes on each question.
Part 2 of this document contains practice questions on a few topics which were not included
in the earlier practices.

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

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

CURSOR getAllObjects (pOwner VARCHAR2) IS


SELECT owner, object_name, object_type
FROM all_objects
WHERE owner = pOwner;
CURSOR objectCount (pOwner VARCHAR2) IS
SELECT COUNT(*)
FROM all_objects
WHERE owner = pOwner;
cmd
VARCHAR2(256);
objCount NUMBER;
objOwner VARCHAR2(30) := 'TST'; -- Define owner here
BEGIN
OPEN objectCount (objOwner);
FETCH objectCount INTO objCount;
CLOSE objectCount;
WHILE objCount > 0 LOOP
FOR objRec IN getAllObjects (objOwner) LOOP
BEGIN
cmd := 'DROP ' || objRec.object_type || ' ' || objRec.owner ||
'.' || objRec.object_name;
DBMS_OUTPUT.PUT(cmd);
EXECUTE IMMEDIATE cmd;
DBMS_OUTPUT.PUT_LINE(' ... dropped');
EXCEPTION WHEN OTHERS THEN
NULL;
END;
END LOOP;
OPEN objectCount (objOwner);
FETCH objectCount INTO objCount;
CLOSE objectCount;
END LOOP;
END;

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their
respective owners.

1. What is the main purpose of the code above?


2. What type of PL/SQL program is it? A procedure, a function or something else?
3. What is objectCount?
4. What is objOwner?
5. What is pOwner?
6. How many loops are being executed?
7. What is the purpose of the cmd variable?
8. What is objCount?
9. Does the program have any error handling, or does it propagate errors to the
calling environment?
10. Why are there two opens of the cursor objectCount?
11. The End Loop in Line 43 refers to which Loop the one in line 23 or the one in
line 24?

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

/* Disable all fk constraints pointing to the table(s) so that the


table(s) can be truncated.
*/
CURSOR get_tables IS
SELECT table_name
FROM user_tables
WHERE table_name = 'GSS%'
OR table_name = NULL;
CURSOR get_constraints(p_table_name VARCHAR2(30) IN) IS
SELECT child.table_name
child.constraint_name
FROM user_constraints parent
user_constraints child
WHERE parent.table_name = p_table_name
AND parent.constraint_name = child.r_constraint_name
AND child.constraint_type = 'R';
conDropCursor INTEGER;
conCreCursor INTEGER;
tabTruncCursor INTEGER;
ignore INTEGER
BEGIN
FOR tabRec IN get_tables LOOPS
-- Disable all foreign key constraints
conDropCursor := dbms_sql.opn_cursor;
FOR conRec IN get_constraints(conRec.table_name) LOOPS
dbms_sql.parse(conDropCursor, 'ALTER TABLE ' || conRec.table_name 32
||
' DISABLE CONSTRAINT ' || conRec.constraint_name,
dbms_sql.v7);
ignore := dbms_sql.execute(conDropCursor);
END LOOP;
dbms_sql.close_cursor(conDropCursor);
-- Truncate tables
tabTruncCursor := dbms_sql.open_cursor;
dbms_sql.parse(tabTruncCursor, 'TRUNCATE TABLE ' ||
tabRec.table_name,
dbms_sql.v7);
ignore := dbms_sql.execute(tabTruncCursor);
dbms_sql.close_cursor(tabTruncCursor);
-- Enable all foreign key constraints
conCreCursor := dbms_sql.open_cursor;
FOR conRec IN get_constraints(conRec.table_name) LOOP
dbms_sql.parse(conCreCursor, 'ALTER TABLE ' || conRec.table_name ||
' ENABLE CONSTRAINT ' || conRec.constraint_name,

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their
respective owners.

51
52
53
54
55
56

dbms_sql.v7);
ignore := dbms_sql.execute(conCreCursor);
END LOOP;
dbms_sql.close_cursor(conCreCursor);
END LOOP;
END;

1. In the PL/SQL program above there are a number of errors. How many can you
find?
To help get started here are some of the lines with errors in: 8, 9, 11,12 14, 23.
Some of the errors are logical errors, some are syntax errors and some are typing
mistakes.
2. Could the program have been written in any other way, using any other
mechanisms other than DBMS_SQL?

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their
respective owners.

PART 2
Some of these questions use a copy of the EMPLOYEES table. Create this copy by
executing:
CREATE TABLE cert_emps AS SELECT * FROM employees;
1.

Using Local Subprograms.

Enter and run the following code, then answer the questions below.
CREATE OR REPLACE PROCEDURE give_salary_raise
(p_employee_id cert_emps.employee_id%TYPE,
p_salary_incr
cert_emps.salary%TYPE)
IS
v_salary_ok BOOLEAN;
FUNCTION check_max_sal
RETURN BOOLEAN
IS
v_max_sal cert_emps.salary%TYPE;
v_new_sal cert_emps.salary%TYPE;
BEGIN
SELECT max(salary) INTO v_max_sal FROM cert_emps;
SELECT (salary + p_salary_incr) INTO v_new_sal
FROM cert_emps WHERE employee_id = p_employee_id;
IF v_new_sal <= v_max_sal THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END check_max_sal;
BEGIN
v_salary_ok := check_max_sal;
-- Line A
IF v_salary_ok THEN
UPDATE cert_emps SET salary = salary + p_salary_incr
WHERE employee_id = p_employee_id;
ELSE
RAISE_APPLICATION_ERROR(-20201, 'New salary exceeds maximum');
END IF;
END give_salary_raise;

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

A. In your own words, explain what a Local Subprogram is. What is the local
subprogram in this code example?
B. What limit does this local subprogram place on salary increases?
C. Invoke the procedure twice as follows:
BEGIN
give_salary_raise(200, 1000);
give_salary_raise(100, 1000);
END;
Which of these salary increases has failed, and why?
D. Will the following invocation succeed or fail? Why ?
DECLARE
v_bool BOOLEAN;
BEGIN
v_bool := check_max_salary;
END;
E. Imagine that the following line of code is added at Line A:
DBMS_OUTPUT.PUT_LINE('New salary is: ' || v_new_sal);
Will this procedure compile now? Why or why not?

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

2.

Using USER_ERRORS.
A. What is the purpose of the USER_ERRORS dictionary table?
B. Enter and run the following code, then display all the compiler errors by
SELECTing from USER_ERRORS:
CREATE OR REPLACE PROCEDURE find_max_sal
IS
v_max_sal employees.salary%TYPE;
BEGIN
SELECT MAX(salary) INTO v_max FROM employees;
DBMS_OUTPUT.PUT_LINE('The maximum salary is: ' || v_max);
END;
C. Now try to create a second procedure using the following code:
CREATE OR REPLACE PROCEDURE find_min_sal
IS
v_min_sal employees.salary%TYP;
BEGIN
SELECT MIN(salary) INTO v_min_sal FROM employees;
DBMS_OUTPUT.PUT_LINE('The minimum salary is: ' || v_min_sal);
END;
D. Display compilation errors in all your procedures using a single SELECT
from USER_ERRORS. Note: in addition to FIND_MAX_SAL and
FIND_MIN_SAL, you may see errors from earlier procedures which failed to
compile.
E. Now correct the error in the FIND_MIN_SAL procedure and recompile it
successfully. Then repeat step D to see all your procedure errors. Why is the
earlier error in FIND_MIN_SAL not displayed?
F. Display all the errors in the FIND_MAX_SAL procedure, together with the
incorrect lines of source code. (Hint: join USER_ERRORS and
USER_SOURCE).

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

3.

Using a Bodiless Package.


Enter and run the following code to create a bodiless package, then answer the
questions below:
CREATE OR REPLACE PACKAGE no_body_pack IS
pi
NUMBER := 3.1415926536;
e_number_too_large
EXCEPTION;
PRAGMA EXCEPTION_INIT(e_number_too_large, -6502);
CURSOR ce_curs IS
SELECT last_name, salary FROM cert_emps
ORDER BY last_name;
END no_body_pack;
A. In your own words, describe the purpose of a bodiless package.
B. Create a procedure to calculate the circumference of a circle from its radius
using the formula: CIRCUMFERENCE = 2 * PI * RADIUS. The procedure
should accept the radius as an IN argument and return the circumference as an
OUT argument. The value of pi must be read from the bodiless package.
Test your procedure by invoking it with a radius of 20, displaying the
circumference rounded to two decimal places.
C. The following procedure may raise an ORA-01438 error. Add a suitable
exception handler to the procedure, create it and invoke it with an IN
argument of 3000.
CREATE OR REPLACE PROCEDURE number_overflow
(p_in
IN
NUMBER)
IS
v_result
NUMBER(6,2);
BEGIN
v_result := p_in * 4;
DBMS_OUTPUT.PUT_LINE('The calculation succeeded');
END;
D. Create a package containing three procedures which use the cursor declared in
the NO_BODY_PACK bodiless package. The first procedure must open the
cursor; the second procedure must fetch and display N rows from the cursor
(where N is an IN argument to the procedure); the third procedure must close
the cursor. Test your package by displaying the first five rows of the
CERT_EMPS table.

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

10

4. Using the REFERENCING and WHEN clauses in Row Triggers.


A. Create table NEW as follows:
CREATE TABLE new
(when
DATE,
which_emp
NUMBER(4),
salary_change NUMBER(8,2));
Now enter and run the following code to create a row trigger:
CREATE OR REPLACE TRIGGER sal_change_trigg
AFTER UPDATE OF salary ON cert_emps
FOR EACH ROW
BEGIN
INSERT INTO new VALUES(SYSDATE, :OLD.employee_id,
:NEW.salary - :OLD.salary);
END;
Test the trigger by executing the following SQL statements:
UPDATE cert_emps SET salary = salary + 100
WHERE department_id = 20;
SELECT * FROM new;
B. Edit the trigger code to use the REFERENCING clause, using
OLDREC and NEWREC as correlation names for OLD and NEW.
Recompile the trigger and test it again as in step A.
C. In your own words, explain why the REFERENCING clause can be
used only with row triggers, not with any other kind of trigger.

D. Enter and run the following code to create another row trigger:
CREATE OR REPLACE TRIGGER sal_change_trigg
BEFORE UPDATE OF salary ON cert_emps
FOR EACH ROW
BEGIN
IF :NEW.job_id <> 'AD_PRES'
AND TO_CHAR(SYSDATE, 'DY') = 'SUN'
THEN
RAISE_APPLICATION_ERROR(-20202,
'Only the President can receive a new salary on Sundays');
END IF;
END;
E. Modify your code to use a WHEN clause, and re-create the trigger.
Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

11

4. Using an INDEX BY Table of Records in a Package.


A. Enter and run the following code, to create a package which declares an
INDEX BY table of records as a global variable:
CREATE OR REPLACE PACKAGE cert_emp_pkg IS
TYPE t_emptab IS TABLE OF cert_emps%ROWTYPE
INDEX BY PLS_INTEGER;
PROCEDURE get_emps(p_emp_tab OUT t_emptab);
END cert_emp_pkg;
CREATE OR REPLACE PACKAGE BODY cert_emp_pkg IS
PROCEDURE get_emps(p_emp_tab OUT t_emptab)
IS
CURSOR emp_curs IS
SELECT * FROM cert_emps
ORDER BY employee_id;
BEGIN
FOR emp_record IN emp_curs LOOP
p_emp_tab(emp_record.employee_id) := emp_record;
END LOOP;
END get_emps;
END cert_emp_pkg;
B. Invoke the package procedure from an anonymous block which displays the
EMPLOYEE_ID and LAST_NAME of all the rows of the CERT_EMPS
table.
C. Modify CERT_EMP_PKG, changing procedure GET_EMPS to a function
which RETURNs the INDEX BY table of records.
D. Modify your anonymous block from step B to call the function and display the
CERT_EMPS rows.

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

12

6. Remote Dependencies.
You cannot test remote dependencies in Application Express because you
would need two distinct databases. Instead, imagine that a second (remote)
database exists. This database contains a procedure called REMOTE_PROC.
You have created a database link, MY_DB_LINK, which points to the remote
database.
In your local APEX database you are using TIMESTAMP mode, and you have
created the following procedure:
CREATE OR REPLACE PROCEDURE local_proc
IS
BEGIN
remote_proc@my_db_link;
END;
A. REMOTE_PROC is recompiled successfully at 11:30, then LOCAL_PROC is
recompiled successfully at 13:15. Then, LOCAL_PROC is invoked twice.
What timestamps are now stored in the two procedures?
B. At 15:00, REMOTE_PROC is again recompiled successfully. Now what
timestamps are stored in the two procedures?
C. At 15:30, LOCAL_PROC is invoked. What will happen, and why? What is
the status of the two procedures now, valid or invalid?
D. At 16:00, LOCAL_PROC is invoked again. What will happen this time, and
why? Now what is the status of the two procedures?
E. In your own words, explain how using SIGNATURE mode would help to
avoid the problem in step C.
F. Which SQL statement must you execute in order to use signature mode? In
which database?

Copyright 2015, Oracle and/or its affiliates. All rights reserved. Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of
their respective owners.

Das könnte Ihnen auch gefallen