100% found this document useful (1 vote)
2K views

PLSQL Practice

This document contains examples and practice questions on PL/SQL fundamentals like blocks, variables, data types, and DML operations. Some key points: - It shows the structure of PL/SQL blocks and valid/invalid variable declarations. Examples demonstrate basic operations like printing output and calculating values. - Practice questions test understanding of scoping rules, nested blocks, data types, and DML statements like INSERT, UPDATE. - Later examples demonstrate accepting user input, retrieving values from tables, and modifying data in PL/SQL blocks. - Scripts provided as solutions can be modified per the instructions and re-executed to learn additional techniques.

Uploaded by

priya raghavi
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
2K views

PLSQL Practice

This document contains examples and practice questions on PL/SQL fundamentals like blocks, variables, data types, and DML operations. Some key points: - It shows the structure of PL/SQL blocks and valid/invalid variable declarations. Examples demonstrate basic operations like printing output and calculating values. - Practice questions test understanding of scoping rules, nested blocks, data types, and DML statements like INSERT, UPDATE. - Later examples demonstrate accepting user input, retrieving values from tables, and modifying data in PL/SQL blocks. - Scripts provided as solutions can be modified per the instructions and re-executed to learn additional techniques.

Uploaded by

priya raghavi
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 26

plsql

--PRACTICE-1
1) Which of the following PL/SQL blocks execute successfully?
a.BEGIN
END;

b.DECLARE
sal INTEGER(10);
END;

c.DECLARE
BEGIN
END;

d.DECLARE
total_sal INTEGER(10);
BEGIN
DBMS_OUTPUT.PUT_LINE(amount);
END;

Ans: c

2) Create and execute a simple anonymous block that outputs “Hello World.”
save this script as Introduction to PL/SQL 02_soln.sql.
begin
dbms_output.put_line('Hello World');
end;
/

--PRACTICE-2

Declaring Variables

1) Identify valid and invalid identifier names:


a.sysdate----invalid
b.v_job_id---valid
c.today’s_date-----invalid
d.Number_of_days_in_December_this_year--invalid
e.Isleap$year--valid
f.#char---invalid
g.VARCHAR#--valid
h.char4to10--valid

2) Identify valid and invalid variable declaration and initialization:


a.number_of_cities PLS_INTEGER;-----valid
b.state_name constant VARCHAR2(10);--invalid
c.ship_to VARCHAR2(10):=Johnson;--invalid
d.by_when DATE:= CURRENT_DATE+1;--valid

3) Examine the following anonymous block and choose the appropriate statement.
DECLARE
v_fname VARCHAR2(20);
v_lname VARCHAR2(15) DEFAULT 'fernandez';
BEGIN
DBMS_OUTPUT.PUT_LINE(v_fname ||' ' ||v_lname);
END;
/
a. The block executes successfully and print “fernandez.”
b. The block returns an error because the fname variable is used without
initializing.
c. The block executes successfully and print “null fernandez.”
d. The block returns an error because you cannot use the DEFAULT keyword to
initialize a variable of type VARCHAR2.
e. The block returns an error because the v_fname variable is not declared.

4) Create an anonymous block. Load the script Introduction to PL/SQL 02_soln.sql,


which you created in question 2 of practice Introduction to PL/SQL.
a. Add a declarative section to this PL/SQL block. In the declarative section,
declare the following variables:
1. Variable v_today of type DATE. Initialize today with SYSDATE.
2. Variable v_tomorrow of type today. Use %TYPE attribute to declare this
variable.
b. In the executable section, initialize the tomorrow variable with an expression,
which calculates tomorrow’s date (add one to the value in today). Print the value
of today and tomorrow after printing “Hello World.”
c. Execute and save this script as Declaring Variables 04_soln.sql. Sample output
is as follows:

declare
v_today DATE:=sysdate;
v_tomorrow v_today%type;
begin
v_tomorrow:=v_today+1;
dbms_output.put_line('Hello world');
dbms_output.put_line('today is :'||v_today);
dbms_output.put_line('Tomorrow is:'||v_tomorrow);
end;
/

5) Edit the Declaring Variables 04_soln.sql script


a. Add code to create two bind variables.
Create bind variables b_basic_percent and b_pf_percent of type NUMBER.
b. In the executable section of the PL/SQL block, assign the values 45 and 12 to
b_basic_percent and b_pf_percent, respectively.
c. Terminate the PL/SQL block with “/” and display the value of the bind variables
by using the PRINT command.
d. Execute and save your script file as Declaring Variables 05_soln.sql. Sample
output is as follows:

variable b_basic_percent number


variable b_pf_percent number
begin
:b_basic_percent:=45;
:b_pf_percent:=12;
end;
/
print b_basic_percent;
print b_pf_percent;
/

--PRACTICE-3
1) Evaluate the preceding PL/SQL block and determine the data type and value of
each of the following variables according to the rules of scoping.
a.The value of weight at position 1 is:
2
The data type is NUMBER.

b.The value of new_locn at position 1 is:


Western Europe
The data type is VARCHAR2.

c.The value of weight at position 2 is:


601
The data type is NUMBER.

d.The value of message at position 2 is:


Product 10012 is in stock. The data type is VARCHAR2.

e.The value of new_locn at position 2 is:


Illegal because new_locn is not visible outside the subblock.

2) DECLARE
customer VARCHAR2(50) := 'Womansport';
credit_rating VARCHAR2(50) := 'EXCELLENT';
BEGIN
DECLARE
customer NUMBER(7) := 201;
name VARCHAR2(25) := 'Unisports'; BEGIN
credit_rating :=‘GOOD’;
END;
END;

In the preceding PL/SQL block, determine the values and data types for each of the
following cases.

a.The value of customer in the nested block is:


201
The data type is NUMBER.F

b.The value of name in the nested block is:


Unisports
The data type is VARCHAR2.

c.The value of credit_rating in the nested block is:


GOOD
The data type is VARCHAR2.

d.The value of customer in the main block is:


Womansport
The data type is VARCHAR2.

e.The value of name in the main block is:


name is not visible in the main block and you would see an error.

f.The value of credit_rating in the main block is:


GOOD
The data type is VARCHAR2.

3) Use the same session that you used to execute the practices in Lesson 2. If you
have opened a new session, then execute lab_02_05_soln.sql. Edit
lab_02_05_soln.sql.
a.Use single line comment syntax to comment the lines that create the bind
variables.

--variable basic percent number


--variable pf percent number

b.Use multiple line comments in the executable section to comment the lines that
assign values to the bind variables.

/*:basic percent:=50;
:pf percent :=20;*/

c.Declare two variables: fname of type VARCHAR2 and size 15, and emp_sal of type
NUMBER and size 10.

fname varchar2(15);
emp_sal number(10);

d.Include the following sql statement in the executable section

select first_name, salary into fname,emp_sal


from employees where employee_id=110;

e.Change the line that prints “Hello World” to print “Hello” and the first name.
You can comment the lines that display the dates and print the bind variables, if
you want to.

dbms_output.put_line('Hello World'||fname);

f.Calculate the contribution of the employee towards provident fund (PF).


PF is 12% of the basic salary, and the basic salary is 45% of the salary. Use the
bind variables for the calculation. Try to use only one expression to calculate the
PF. Print the employee’s salary and his contribution toward PF

DBMS_OUTPUT.PUT_LINE('YOUR SALARY IS : '||emp_sal);


DBMS_OUTPUT.PUT_LINE('YOUR CONTRIBUTION TOWARDS PF:'||
emp_sal*:basic_percent/100*:pf_percent/100);

g.Execute and save your script as lab_03_03_soln.sql. Sample output is as follows:

4) Accept a value at run time using the substitution variable. In this practice,
you will modify the script lab_03_04.sql to accept user input.
a.Load the script lab_03_04.sql file.
b.Include the PROMPT command to prompt the user with the following message: “Please
enter your employee number.”

accept empno prompt 'please enter your employee number:'

c.Modify the declaration of the empno variable to accept the user input.

empno number(6):=&empno;

d.Modify the select statement to include the substitution variable empno.

SELECT first_name, salary INTO fname, emp_sal


FROM employees WHERE employee_id=empno;

5) Execute the script lab_03_05.sql. This script creates a table called


employee_details.
a.The employee and employee_details tables have the same data. You will update the
data in the employee_details table. Do not update or change the data in the
employees table.
b.Open the script lab_03_05b.sql and observe the code in the file. Note that the
code accepts the employee number and the department number from the user.

SET SERVEROUTPUT ON
ACCEPT emp_id PROMPT 'Please enter your employee number';
ACCEPT emp_deptid PROMPT 'Please enter the department number for which salary
revision is being done';

DECLARE
emp_authorization NUMBER(5);
emp_id NUMBER(5):=&emp_id;
emp_deptid NUMBER(6):=&emp_deptid;
no_such_employee EXCEPTION;
end;
/

--PRACTICE-4
1) Create a PL/SQL block that selects the maximum department ID in the departments
table and stores it in the max_deptno variable. Display the maximum department ID.
a.Declare a variable max_deptno of type NUMBER in the declarative section.
b.Start the executable section with the keyword BEGIN and include a SELECT
statement to retrieve the maximum department_id from the departments table.
c.Display max_deptno and end the executable block.
Execute and save your script as lab_04_01_soln.sql. Sample output is as follows:

declare
max_deptno number;
begin
select max(department_id) into max_deptno from departments;
dbms_output,put_line('the maximum department_id is :'||ma_deptno);
end;
/

2) Modify the PL/SQL block you created in exercise 1 to insert a new department
into the
departments table.
a.Load the script lab_04_01_soln.sql. Declare two variables: dept_name of type
departments.department_name. Bind variable dept_id of type NUMBER.
Assign ‘Education’ to dept_name in the declarative section.

variable dept_id number


dept_name department.department_name%type :='Education';

b.You have already retrieved the current maximum department number from the
departments table. Add 10 to it and assign the result to dept_id.

:dept_id:=10+max_deptno;

c.Include an INSERT statement to insert data into the department_name,


department_id, and location_id columns of the departments table. Use values in
dept_name, dept_id for department_name, department_id and use NULL for location_id.

insert into departments(department_id,department_name,location_id)


values (:dept_id,dept_name,NULL);
d.Use the SQL attribute SQL%ROWCOUNT to display the number of rows that are
affected.

dbms_output.put_line('SQL%ROWCOUNT gives'||SQL%ROWCOUNT);

e.Execute a select statement to check if the new department is inserted. You can
terminate the PL/SQL block with “/” and include the SELECT statement in your
script.

select * from departments where department_id=:dept_id;

3) In exercise 2, you set location_id to null. Create a PL/SQL block that updates
the location_id to 3000 for the new department. Use the bind variable dept_id to
update the row.
Note: Skip step a if you have not started a new iSQL*Plus session for this
practice.
a.If you have started a new iSQL*Plus session, delete the department that you have
added to the departments table and execute the script lab_04_02_soln.sql.

delete from departments where department_id =280;

b.Start the executable block with the keyword BEGIN. Include the UPDATE statement
to set the location_id to 3000 for the new department. Use the bind variable
dept_id in your UPDATE statement.

begin
update departments set location_id=3000
where department_id=:dept_id;
end;
/

c.End the executable block with the keyword END. Terminate the PL/SQL block with
“/” and include a SELECT statement to display the department that you updated.

select * from departments where department_id=:dept_id;

d.Include a DELETE statement to delete the department that you added.

delete from departments where department_id=:dept_id;

4) Load the script lab_03_05b.sql to the iSQL*Plus workspace.


a.Observe that the code has nested blocks. You will see the declarative section of
the outer block. Look for the comment “INCLUDE EXECUTABLE SECTION OF OUTER BLOCK
HERE” and start an executable section.
b.Include a single SELECT statement, which retrieves the employee_id of the
employee working in the “Human Resources” department. Use the INTO clause to store
the retrieved value in the variable emp_authorization.
c.Save your script as lab_04_04_soln.sql.

begin
select employee_id into emp_authorization from
employee_details where department_id=(select department_id
from departments where department_name='Human Resources');

--PRACTICE-5

1) Execute the command in the file lab_05_01.sql to create the messages table.
Write a PL/SQL block to insert numbers into the messages table.
a.Insert the numbers 1 to 10, excluding 6 and 8.
b.Commit before the end of the block.

begin
for i in 1..10 loop
if i = 6 or i =8 then
null;
else
insert into message(results) values (i);
end if;
end loop;
commit;
end;
/

c.Execute a SELECT statement to verify that your PL/SQL block worked.

select * from messages;

2) Execute the script lab_05_02.sql. This script creates an emp table that is a
replica of the employees table. It alters the emp table to add a new column, stars,
of VARCHAR2 data type and size 50. Create a PL/SQL block that inserts an asterisk
in the stars column for every
$1000 of the employee’s salary. Save your script as lab_05_02_soln.sql.
a.Use the DEFINE command to define a variable called empno and initialize it to
176.

create table emp as


select * from employees;

alter table emp


add stars varchar2(50);

DEFINE empno=176;

b.Start the declarative section of the block and pass the value of empno to the
PL/SQL block through an iSQL*Plus substitution variable. Declare a variable
asterisk of type emp.stars and initialize it to NULL. Create a variable sal of type
emp.salary.
c.In the executable section, write logic to append an asterisk (*) to the string
for every
$1000 of the salary. For example, if the employee earns $8000, the string of
asterisks should contain eight asterisks. If the employee earns $12500, the string
of asterisks should contain 13 asterisks.

declare
v_empno emp.employee_id%type:=to_number(&empno);
v_asterisk emp.stars%type:=null;
v_sal emp.salary%type;
begin
select nvl(round(salary/1000),0) into v_sal
from emp where employee_id=v_empno;
for i in 1..v_sal loop
v_asterisk:=v_asterisk||'*';
end loop;
end;
/

d.Update the stars column for the employee with the string of asterisks. Commit
before the end of the block.
update emp set stars=v_asterisk
where employee_id=v_empno;
commit;

e.Display the row from the emp table to verify whether your PL/SQL block has
executed successfully.

select employee_id,salary,stars from emp


where employee_id=176;

3) Load the script lab_04_04_soln.sql, which you created in exercise 4 of Practice


4.
a.Look for the comment “INCLUDE SIMPLE IF STATEMENT HERE” and include a simple IF
statement to check if the values of emp_id and emp_authorization are the same.

if(emp_id=emp_authorization) then

--PRACTICE-6

1) Write a PL/SQL block to print information about a given country.


a.Declare a PL/SQL record based on the structure of the countries table.
b.Use the DEFINE command to define a variable countryid. Assign CA to countryid.
Pass the value to the PL/SQL block through an iSQL*Plus substitution variable.
c.In the declarative section, use the %ROWTYPE attribute and declare the variable
country_record of type countries.
d.In the executable section, get all the information from the countries table by
using countryid. Display selected information about the country. Sample output is
as follows:

define countryid=CA
declare
country_record countries%rowtype;
begin
select * into country_record from countries
where country_id =upper('&countryid');
dbms_output.put_line('country id :' || country_record.country_id||
'country name:'||country_record.country_name||
'region:'||country_record.region_id);
end;
/

2) Create a PL/SQL block to retrieve the name of some departments from the
departments table and print each department name on the screen, incorporating an
INDEX BY table. Save the script as lab_06_02_soln.sql.
a.Declare an INDEX BY table dept_table_type of type departments.department_name.
Declare a variable my_dept_table of type dept_table_type to temporarily store the
name of the departments.
b.Declare two variables: loop_count and deptno of type NUMBER. Assign 10 to
loop_count and 0 to deptno.
c.Using a loop, retrieve the name of 10 departments and store
the names in the INDEX BY table. Start with department_id 10.
Increase deptno by 10 for every iteration of the loop.
The following table shows the department_id for which you
should retrieve the department_name and store in the INDEX BY table.
DEPARTMENT_ID DEPARTMENT_NAME
10 Administration
20 Marketing
30 Purchasing
40 Human Resources
50 Shipping
60 IT
70 Public Relations
80 Sales
90 Executive
100 Finance
d.Using another loop, retrieve the department names from the INDEX BY table and
display them.
e.Execute and save your script as lab_06_02_soln.sql. The output is as follows:

DECLARE
TYPE dept_table_type is table of departments.department_name%TYPE INDEX BY
PLS_INTEGER;
my_dept_table dept_table_type;

loop_count number(2):=10;
deptno number(4):=0;

BEGIN
FOR i IN 1..loop_count LOOP
deptno:=deptno+10;
SELECT department_name INTO my_dept_table(i)
FROM departments
WHERE department_id = deptno;
END LOOP;

FOR i IN 1..loop_count LOOP


DBMS_OUTPUT.PUT_LINE (my_dept_table(i));
END LOOP;
END;
/

3) Modify the block that you created in exercise 2 to retrieve all information
about each department from the departments table and display the information. Use
an INDEX BY table of records.
a.Load the script lab_06_02_soln.sql.
b.You have declared the INDEX BY table to be of type departments.department_name.
Modify the declaration of the INDEX BY table, to temporarily store the number,
name, and location of all the departments. Use the %ROWTYPE attribute.
c.Modify the select statement to retrieve all department information currently in
the
departments table and store it in the INDEX BY table.
d.Using another loop, retrieve the department information from the INDEX BY table
and display the information. Sample output is as follows

DECLARE
TYPE dept_table_type is table of departments%ROWTYPE INDEX BY PLS_INTEGER;
my_dept_table dept_table_type;
loop_count NUMBER (2):=10;
deptno NUMBER (4):=0;
BEGIN
FOR i IN 1..loop_count LOOP
deptno := deptno + 10; SELECT *
INTO my_dept_table(i) FROM departments
WHERE department_id = deptno;
END LOOP;
FOR i IN 1..loop_count LOOP
DBMS_OUTPUT.PUT_LINE ('Department Number: ' || my_dept_table(i).department_id
|| ' Department Name: ' || my_dept_table(i).department_name
|| ' Manager Id: '|| my_dept_table(i).manager_id
|| ' Location Id: ' || my_dept_table(i).location_id); END
LOOP;
END;
/

4) Load the script lab_05_03_soln.sql.


a.Look for the comment “DECLARE AN INDEX BY TABLE OF TYPE VARCHAR2(50). CALL IT
ename_table_type” and include the declaration.
b.Look for the comment “DECLARE A VARIABLE ename_table OF TYPE ename_table_type”
and include the declaration.

TYPE ename_table_type IS TABLE OF


VARCHAR2(50) INDEX BY PLS_INTEGER;
ename_table ename_table_type;

--PRACTICE-7

1) Create a PL/SQL block that determines the top n salaries of the employees.
a.Execute the script lab_07_01.sql to create a new table, top_salaries, for storing
the salaries of the employees.
b.Accept a number n from the user where n represents the number of top n earners
from the employees table. For example, to view the top five salaries, enter 5.
Note: Use the DEFINE command to define a variable p_num to provide the value for
n. Pass the value to the PL/SQL block through an iSQL*Plus substitution variable.

DELETE FROM top_salaries;


DEFINE p_num = 5

c.In the declarative section, declare two variables: num of type NUMBER to accept
the substitution variable p_num, sal of type employees.salary. Declare a cursor,
emp_cursor that retrieves the salaries of employees in descending order. Remember
that the salaries should not be duplicated.
d.In the executable section, open the loop and fetch top n salaries and insert them
into top_salaries table. You can use a simple loop to operate on the data. Also,
try and use %ROWCOUNT and %FOUND attributes for the exit condition.

DECLARE
num NUMBER(3) := &p_num;
sal employees.salary%TYPE;
CURSOR emp_cursor IS
SELECT distinct salary
FROM employees
ORDER BY salary DESC;
BEGIN
OPEN emp_cursor;
FETCH emp_cursor INTO sal;
WHILE emp_cursor%ROWCOUNT <= num AND emp_cursor%FOUND LOOP
INSERT INTO top_salaries (salary)
VALUES (sal);
FETCH emp_cursor INTO sal;
END LOOP;
CLOSE emp_cursor;
END;

e.After inserting into the top_salaries table, display the rows with a SELECT
statement. The output shown represents the five highest salaries in the employees
table.
SELECT * FROM top_salaries;

2) Create a PL/SQL block that does the following:


a.Use the DEFINE command to define a variable p_deptno to provide the department
ID.
DEFINE p_deptno = 10

b.In the declarative section, declare a variable deptno of type NUMBER and assign
the value of p_deptno.
c.Declare a cursor, emp_cursor that retrieves the last_name, salary, and
manager_id of the employees working in the department specified in deptno.
d.In the executable section use the cursor FOR loop to operate on the data
retrieved. If the salary of the employee is less than 5000 and if the manager ID is
either 101 or 124, display the message <<last_name>> Due for a raise. Otherwise,
display the message <<last_name>> Not due for a raise.

declare
deptno number:=&p_deptno
cursor emp_cursor is
select last_name,salary,manager_id
from employees
where department_id=deptno;
begin
for emp_record in emp_cursor loop
if emp_record.salary<5000 and (emp_record.manager_id=101 or
emp_record.manager_id=124) then
dbms_output.put_line(emp_record.last_name||'due for a raise');
else
dbms_output.put_line(emp_record.last_name||'not due for a raise');
end if;
end loop;
end;
/

3) Write a PL/SQL block, which declares and uses cursors with parameters.
a.In a loop, use a cursor to retrieve the department number and the department name
from the departments table for a department whose department_id is less than 100.
Pass the department number to another cursor as a parameter to retrieve from the
employees table the details of employee last name, job, hire date, and salary of
those employees whose employee_id is less than 120 and who work in that department.
In the declarative section declare a cursor dept_cursor to retrieve department_id,
department_name for those departments with department_id less than 100. Order by
department_id.
DECLARE
CURSOR dept_cursor IS
SELECT department_id,department_name FROM departments
WHERE department_id < 100
ORDER BY department_id;

b.Declare another cursor emp_cursor that takes the department number as parameter
and retrieves last_name, job_id, hire_date, and salary of those employees with
employee_id of less than 120 and who work in that department
c.Declare variables to hold the values retrieved from each cursor. Use the %TYPE
attribute while declaring variables.
d.Open the dept_cursor, use a simple loop and fetch values into the variables
declared. Display the department number and department name.
e.For each department, open the emp_cursor by passing the current department number
as a parameter. Start another loop and fetch the values of emp_cursor into
variables and print all the details retrieved from the employees table.
Note: You may want to print a line after you have displayed the details of each
department. Use appropriate attributes for the exit condition. Also check if a
cursor is already open before opening the cursor.
f.Close all the loops and cursors, and end the executable section. Execute the
script.

CURSOR emp_cursor(v_deptno NUMBER) IS


SELECT last_name,job_id,hire_date,salary FROM employees
WHERE department_id = v_deptno
AND employee_id < 120;

current_deptno departments.department_id%TYPE;
current_dname departments.department_name%TYPE;
ename employees.last_name%TYPE;
job employees.job_id%TYPE;
hiredate employees.hire_date%TYPE;
sal employees.salary%TYPE;

BEGIN
OPEN dept_cursor;
LOOP
FETCH dept_cursor INTO current_deptno,current_dname;
EXIT WHEN dept_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE ('Department Number : ' ||
current_deptno ||
'Department Name : ' || current_dname);
IF emp_cursor%ISOPEN THEN CLOSE emp_cursor;
END IF;
OPEN emp_cursor (current_deptno); LOOP
FETCH emp_cursor INTO ename,job,hiredate,sal; EXIT WHEN emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (ename || ' ' || job || ' ' || hiredate
|| ' ' || sal);
END LOOP;
DBMS_OUTPUT.PUT_LINE('--------------------------------------------------
--------------------------------------');
CLOSE emp_cursor;
END LOOP;
CLOSE dept_cursor;
END;

4) Load the script lab_06_04_soln.sql.


a.Look for the comment “DECLARE A CURSOR CALLED emp_records TO HOLD salary,
first_name, and last_name of employees” and include the declaration. Create the
cursor such that it retrieves the salary, first_name, and last_name of employees in
the department specified by the user (substitution variable emp_deptid). Use the
FOR UPDATE clause.
b.Look for the comment “INCLUDE EXECUTABLE SECTION OF INNER BLOCK HERE” and start
the executable block.
c.Only employees working in the departments with department_id 20, 60, 80,100, and
110 are eligible for raises this quarter. Check if the user has entered any of
these department IDs. If the value does not match, display the message “SORRY, NO
SALARY REVISIONS FOR EMPLOYEES IN THIS DEPARTMENT.” If the value matches, open the
cursor emp_records.
d.Start a simple loop and fetch the values into emp_sal, emp_fname, and
emp_lname. Use %NOTFOUND for the exit condition.
e.Include a CASE expression. Use the following table as reference for the
conditions in the WHEN clause of the CASE expression.
Note: In your CASE expressions use the constants such as c_range1, c_hike1
that are already declared.

salary Hike percentage


< 6500 20
> 6500 < 9500 15
> 9500 <12000 8
>12000 3
For example, if the salary of the employee is less than 6500, then increase the
salary by 20 percent. In every WHEN clause, concatenate the first_name and
last_name of the employee and store it in the INDEX BY table. Increment the value
in variable i so that you can store the string in the next location. Include an
UPDATE statement with the WHERE CURRENT OF clause.
f.Close the loop. Use the %ROWCOUNT attribute and print the number of records that
were modified. Close the cursor.
g.Include a simple loop to print the names of all the employees whose salaries were
revised.
Note: You already have the names of these employees in the INDEX BY table. Look for
the comment “CLOSE THE INNER BLOCK” and include an END IF statement and an END
statement.

CURSOR emp_records IS SELECT salary,first_name,last_name


FROM employee_details WHERE department_id=emp_deptid
FOR UPDATE;
BEGIN
IF (emp_deptid NOT IN (20,60,80,100,110)) THEN DBMS_OUTPUT.PUT_LINE ('SORRY, NO
SALARY REVISIONS FOR EMPLOYEES IN THIS DEPARTMENT');
ELSE
OPEN emp_records;
LOOP
FETCH emp_records INTO emp_sal,emp_fname,emp_lname;
EXIT WHEN emp_records%NOTFOUND;
CASE
WHEN emp_sal<c_range1 THEN ename_table(i):=emp_fname||' '||emp_lname; i:=i+1;
UPDATE employee_details SET salary=emp_sal + (emp_sal*c_hike1) WHERE CURRENT OF
emp_records;
WHEN emp_sal<c_range2 THEN ename_table(i):=emp_fname||' '||emp_lname; i:=i+1;
UPDATE employee_details SET salary=emp_sal+(emp_sal*c_hike2) WHERE CURRENT OF
emp_records;
WHEN (emp_sal<c_range3) THEN ename_table(i):=emp_fname||' '||emp_lname; i:=i+1;
UPDATE employee_details SET salary=emp_sal+(emp_sal*c_hike3) WHERE CURRENT OF
emp_records;
ELSE
ename_table(i):=emp_fname||' '||emp_lname; i:=i+1;
UPDATE employee_details SET salary=emp_sal+(emp_sal*c_hike4) WHERE CURRENT OF
emp_records;
END CASE;
END LOOP;

DBMS_OUTPUT.PUT_LINE ('NUMBER OF RECORDS MODIFIED :


'||emp_records%ROWCOUNT); CLOSE emp_records;
DBMS_OUTPUT.PUT_LINE ('The following employees'' salaries are updated'); FOR i IN
ename_table.FIRST..ename_table.LAST
LOOP
DBMS_OUTPUT.PUT_LINE(ename_table(i)); END LOOP;
END IF;
END;
/
--PRACTICE-8

1) The purpose of this example is to show the usage of predefined exceptions. Write
a PL/SQL block to select the name of the employee with a given salary value.
a.Delete all the records in the messages table. Use the DEFINE command to define a
variable sal and initialize it to 6000.
b.In the declarative section declare two variables: ename of type
employees.last_name and emp_sal of type employees.salary. Pass the value of the
substitution variables to emp_sal.
c.In the executable section retrieve the last names of employees whose salaries are
equal to the value in emp_sal.
Note: Do not use explicit cursors.
If the salary entered returns only one row, insert into the messages table the
employee’s name and the salary amount.
d.If the salary entered does not return any rows, handle the exception with an
appropriate exception handler and insert into the messages table the message “No
employee with a salary of <salary>.”
e.If the salary entered returns more than one row, handle the exception with an
appropriate exception handler and insert into the messages table the message “More
than one employee with a salary of <salary>.”
f.Handle any other exception with an appropriate exception handler and insert into
the
messages table the message “Some other error occurred.”

DEFINE sal = 6000


DECLARE
ename employees.last_name%TYPE;
emp_sal employees.salary%TYPE := &sal;
BEGIN
SELECT last_name INTO ename
FROM employees
WHERE salary = emp_sal; INSERT INTO messages (results)
VALUES (ename || ' - ' || emp_sal);
EXCEPTION
WHEN no_data_found THEN
INSERT INTO messages (results)
VALUES ('No employee with a salary of '|| TO_CHAR(emp_sal));
WHEN too_many_rows THEN
INSERT INTO messages (results)
VALUES ('More than one employee with a salary of '|| TO_CHAR(emp_sal));
WHEN others THEN
INSERT INTO messages (results)
VALUES ('Some other error occurred.');
END;
/

g.Display the rows from the messages table to check whether the PL/SQL block has
executed successfully. Sample output is as follows:
select * from message;

2) The purpose of this example is to show how to declare exceptions with a standard
Oracle Server error. Use the Oracle server error ORA-02292 (integrity constraint
violated – child record found).
a.In the declarative section declare an exception childrecord_exists. Associate the
declared exception with the standard Oracle server error –02292.
b.In the executable section display “Deleting department 40. ”. Include a
DELETE
statement to delete the department with department_id 40.
c.Include an exception section to handle the childrecord_exists exception and
display the appropriate message. Sample output is as follows:

DECLARE
childrecord_exists EXCEPTION;
PRAGMA EXCEPTION_INIT(childrecord_exists, -02292);
BEGIN
DBMS_OUTPUT.PUT_LINE(' Deleting department 40. ');
delete from departments where department_id=40;
EXCEPTION
WHEN childrecord_exists THEN
DBMS_OUTPUT.PUT_LINE(' Cannot delete this department. There are employees in this
department (child records exist.)');
END;
/

3) Load the script lab_07_04_soln.sql.


a.Observe the declarative section of the outer block. Note that the
no_such_employee exception is declared.
b.Look for the comment “RAISE EXCEPTION HERE.” If the value of emp_id is not
between 100 and 206, then raise the no_such_employee exception.
c.Look for the comment “INCLUDE EXCEPTION SECTION FOR OUTER BLOCK” and handle the
exceptions no_such_employee and too_many_rows. Display appropriate messages when
the exceptions occur. The employees table has only one employee working in the HR
department and therefore the code is written accordingly. The too_many_rows
exception is handled to indicate that the select statement retrieves more than one
employee working in the HR department.
d.Close the outer block.

IF (emp_id NOT BETWEEN 100 AND 206) THEN


RAISE no_such_employee; END IF;
EXCEPTION
WHEN no_such_employee THEN
DBMS_OUTPUT.PUT_LINE ('NO EMPLOYEE EXISTS WITH THE GIVEN EMPLOYEE NUMBER: PLEASE
CHECK');

WHEN TOO_MANY_ROWS THEN


DBMS_OUTPUT.PUT_LINE (' THERE IS MORE THAN ONE EMPLOYEE IN THE HR DEPARTMENT.
');
END;

--PRACTICE-9

1) In iSQL*Plus, load the script lab_02_04_soln.sql that you created for exercise 4
of practice 2.
a.Modify the script to convert the anonymous block to a procedure called greet.
b.Execute the script to create the procedure.
c.Save this script as lab_09_01_soln.sql.
d.Click the Clear button to clear the workspace.
e.Create and execute an anonymous block to invoke the procedure greet. Sample
output is as follows:

CREATE PROCEDURE greet IS


today DATE:=SYSDATE;
tomorrow today%TYPE;
BEGIN
greet;
END;
/
2) Load the script lab_09_01_soln.sql.
a.Drop the procedure greet by issuing the following command:
b.Modify the procedure to accept an argument of type VARCHAR2. Call the argument
name.
c.Print Hello <name> instead of printing Hello World.
d.Save your script as lab_09_02_soln.sql.
e.Execute the script to create the procedure.

DROP PROCEDURE greet

CREATE PROCEDURE greet(name VARCHAR2) IS


today DATE:=SYSDATE;
tomorrow today%TYPE;
BEGIN
tomorrow:=today +1;
DBMS_OUTPUT.PUT_LINE(' Hello '|| name);
end;
/

--PDF-5
--PRACTICE-I(Introduction)

1) Launch iSQL*Plus using the icon provided on your desktop.

a.Log in to the database by using the username and database connect string details
provided by your instructor (optionally, write the information here for your
records):
Username: ora
Password: ora
Database Connect String/Tnsname: t1

b.Execute basic SELECT statements to query the data in the DEPARTMENTS, EMPLOYEES,
and JOBS tables. Take a few minutes to familiarize yourself with the data, or
consult Appendix B, which provides a description and some data from each table in
the Human Resources schema.

select * from departments;


select * from employees;

2) Create a procedure called HELLO to display the text Hello World.


a.Create a procedure called HELLO.
b.In the executable section, use the DBMS_OUTPUT.PUT_LINE procedure to print
Hello World, and save the code in the database.
Note: If you get compile-time errors, then edit the PL/SQL to correct the code, and
replace the CREATE keyword with the text CREATE OR REPLACE.

CREATE PROCEDURE hello IS


BEGIN
DBMS_OUTPUT.PUT_LINE('Hello World');
END;
/
c.Execute the SET SERVEROUTPUT ON command to ensure that the output from the
DBMS_OUTPUT.PUT_LINE procedure will be displayed in iSQL*Plus.
d.Create an anonymous block to invoke the stored procedure.

SET SERVEROUTPUT ON
BEGIN
hello;
END;
/

3) Create a function called TOTAL_SALARY to compute the sum of all employee


salaries.

a.Create a function called TOTAL_SALARY that returns a NUMBER.


b.In the executable section, execute a query to store the total salary of all
employees in a local variable that you declare in the declaration section. Return
the value stored in the local variable. Compile the code.
c.Use an anonymous block to invoke the function. To display the result computed by
the function, use the DBMS_OUTPUT.PUT_LINE procedure.
Hint: Either nest the function call inside the DBMS_OUTPUT.PUT_LINE parameter, or
store the function result in a local variable of the anonymous block and use the
local variable in the DBMS_OUTPUT.PUT_LINE procedure.

CREATE FUNCTION total_salary RETURN NUMBER IS total employees.salary%type;


BEGIN
SELECT SUM(salary) INTO total FROM employees;
RETURN total;
END;
/

DECLARE
total number := total_salary;
BEGIN
DBMS_OUTPUT.PUT_LINE('Total Salary: '|| total);
END;
/

4) Launch SQL*Plus using the icon that is provided on your desktop.

a.Invoke the procedure and function that you created in exercises 2 and 3.

EXECUTE hello;

CREATE PROCEDURE hello_again is


dbms_output.put_line('hello world again');
end;
EXECUTE DBMS_OUTPUT.PUT_LINE('Total Salary: '|| total_salary);

b.Create a new procedure called HELLO_AGAIN to print Hello World again.

c.Invoke the HELLO_AGAIN procedure with an anonymous block.

BEGIN
hello_again;
END;
/

--PRACTICE-1

1) Create and invoke the ADD_JOB procedure and consider the results.

a.Create a procedure called ADD_JOB to insert a new job into the JOBS table.
Provide the ID and title of the job using two parameters.

CREATE OR REPLACE PROCEDURE add_job (


jobid jobs.job_id%TYPE,
jobtitle jobs.job_title%TYPE) IS
BEGIN
INSERT INTO jobs (job_id, job_title)
VALUES (jobid, jobtitle);
COMMIT;
END add_job;
/
b.Compile the code, and invoke the procedure with IT_DBA as job ID and Database
Administrator as job title. Query the JOBS table to view the results.

c.Invoke your procedure again, passing a job ID of ST_MAN and a job title of Stock
Manager. What happens and why?

EXECUTE add_job ('ST_MAN', 'Stock Manager')


BEGIN
add_job ('ST_MAN', 'Stock Manager');
END;

2) Create a procedure called UPD_JOB to modify a job in the JOBS table.

a.Create a procedure called UPD_JOB to update the job title. Provide the job ID and
a new title using two parameters. Include the necessary exception handling if no
update occurs.

CREATE OR REPLACE PROCEDURE upd_job(


jobid IN jobs.job_id%TYPE,
jobtitle IN jobs.job_title%TYPE) IS BEGIN
UPDATE jobs
SET job_title = jobtitle WHERE job_id = jobid;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20202, 'No job updated.'); END IF;
END upd_job;
/

b.Compile the code; invoke the procedure to change the job title of the job ID
IT_DBA to
Data Administrator. Query the JOBS table to view the results.

EXECUTE upd_job ('IT_DBA', 'Data Administrator')

SELECT * FROM jobs WHERE job_id = 'IT_DBA';

3) Create a procedure called DEL_JOB to delete a job from the JOBS table.

a.Create a procedure called DEL_JOB to delete a job. Include the necessary


exception handling if no job is deleted.
b.Compile the code; invoke the procedure using job ID IT_DBA. Query the JOBS table
to view the results.

Also, check the exception handling by trying to delete a job that does not exist.
(Use the IT_WEB job ID.) You should get the message that you used in the exception-
handling section of the procedure as output.

CREATE OR REPLACE PROCEDURE del_job (jobid jobs.job_id%TYPE) IS BEGIN


DELETE FROM jobs
WHERE job_id = jobid; IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20203, 'No jobs deleted.');
END IF;
END DEL_JOB;
/

EXECUTE del_job ('IT_WEB')


BEGIN
del_job ('IT_WEB');
END;
/

4) Create a procedure called GET_EMPLOYEE to query the EMPLOYEES table, retrieving


the salary and job ID for an employee when provided with the employee ID.

a.Create a procedure that returns a value from the SALARY and JOB_ID columns for a
specified employee ID. Compile the code and remove the syntax errors.

CREATE OR REPLACE PROCEDURE get_employee


(empid IN employees.employee_id%TYPE,
sal OUT employees.salary%TYPE,
job OUT employees.job_id%TYPE) IS
BEGIN
SELECT salary, job_id INTO sal, job
FROM employees
WHERE employee_id = empid;
END get_employee;
/

b. Execute the procedure using host variables for the two OUT parameters, one for
the salary and the other for the job ID. Display the salary and job ID for employee
ID 120.

VARIABLE salary NUMBER


VARIABLE job VARCHAR2(15)
EXECUTE get_employee(120, :salary, :job)
PRINT salary job

BEGIN
get_employee(300,:salary,:job);
END;
/

--PRACTICE-2

1) Create and invoke the GET_JOB function to return a job title.

a.Create and compile a function called GET_JOB to return a job title.

CREATE OR REPLACE FUNCTION get_job (jobid IN jobs.job_id%type )


RETURN jobs.job_title%type IS title jobs.job_title%type;
BEGIN
SELECT job_title INTO title
FROM jobs
WHERE job_id = jobid; RETURN title;
END get_job;
/

b.Create a VARCHAR2 host variable called TITLE, allowing a length of 35 characters.


Invoke the function with SA_REP job ID to return the value in the host variable.
Print the host variable to view the result.

VARIABLE title VARCHAR2(35)


EXECUTE :title := get_job ('SA_REP');
PRINT title

2) Create a function called GET_ANNUAL_COMP to return the annual salary computed


from an employee’s monthly salary and commission passed as parameters.

a.Develop and store the function GET_ANNUAL_COMP, accepting parameter values for
monthly salary and commission. Either or both values passed can be NULL, but the
function should still return a non-NULL annual salary. Use the following basic
formula to calculate the annual salary:
(salary*12) + (commission_pct*salary*12)

CREATE OR REPLACE FUNCTION get_annual_comp(


sal IN employees.salary%TYPE,
comm IN employees.commission_pct%TYPE) RETURN NUMBER IS
BEGIN
RETURN (NVL(sal,0) * 12 + (NVL(comm,0) * nvl(sal,0) * 12));
END get_annual_comp;
/

b.Use the function in a SELECT statement against the EMPLOYEES table for employees
in department 30.

SELECT employee_id, last_name, get_annual_comp(salary,commission_pct) "Annual


Compensation"
FROM employees
WHERE department_id=30

3) Create a procedure, ADD_EMPLOYEE, to insert a new employee into the EMPLOYEES


table. The procedure should call a VALID_DEPTID function to check whether the
department ID specified for the new employee exists in the DEPARTMENTS table.

a.Create a function VALID_DEPTID to validate a specified department ID and return a


BOOLEAN value of TRUE if the department exists.

CREATE OR REPLACE FUNCTION valid_deptid(


deptid IN departments.department_id%TYPE)
RETURN BOOLEAN IS

dummy pls integer;

begin
select 1 into dummy from departments
where department_id=deptid;
return true;
exception
when no_data_found then
return false;
end valid deptid;
/

b.Create the ADD_EMPLOYEE procedure to add an employee to the EMPLOYEES table. The
row should be added to the EMPLOYEES table if the VALID_DEPTID function returns
TRUE; otherwise, alert the user with an appropriate message. Provide the following
parameters (with defaults specified in parentheses): first_name, last_name, email,
job (SA_REP), mgr (145), sal (1000), comm (0), and deptid (30). Use the
EMPLOYEES_SEQ sequence to set the employee_id column, and set hire_date to
TRUNC(SYSDATE).
CREATE OR REPLACE PROCEDURE add_employee(
first_name employees.first_name%TYPE,
last_name employees.last_name%type,
email employees.email%type,
job employees.job%type default 'SA_REP',
mgr employees.manager%type default 145,
sal employees.salary%type defauls 1000,
comm employees.commission_pct%type defauls 0,
deptid employees.department_id%type default 30) is
begin
if valid_deptid(deptid) then
insert into
employees(employee_id,first_name,last_name,email,job_id,manager_id,hire_date,salary
,commissiom_pct,department_id)
values (employees
seq.NEXTVAL,first_name,last_name,email,job,mgr,trunc(sysdate),sal,comm,deptid);
else
raise_application_error(-20204,'invalid department id. try again.');
end if;
end add_employee;
/

c.Call ADD_EMPLOYEE for the name Jane Harris in department 15, leaving other
parameters with their default values. What is the result?

Note: If the database server time is not between 8:00 and 18:00, the
Secure_employees trigger will be fired on performing any DML operation on the
EMPLOYEES table. Disable the aforesaid trigger to overcome this problem.

EXECUTE add_employee('Jane', 'Harris', 'JAHARRIS', deptid=> 15)

BEGIN
add_employee('Jane', 'Harris', 'JAHARRIS', deptid=> 15);
END;

d.Add another employee named Joe Harris in department 80, leaving the remaining
parameters with their default values. What is the result?

EXECUTE add_employee('Joe', 'Harris', 'JAHARRIS', deptid=> 80)

--PRACTICE-3

1.Create a package specification and body called JOB_PKG, containing a copy of your
ADD_JOB, UPD_JOB, and DEL_JOB procedures, as well as your GET_JOB function.
Tip: Consider saving the package specification and body in two separate files (for
example,
p3q1_s.sql and p3q1_b.sql for the package specification and body, respectively).
Include a SHOW ERRORS statement after the CREATE PACKAGE statement in each file.
Alternatively, place all code in one file.
Note: Use the code in your previously saved script files when creating the package.
a.Create the package specification including the procedures and function headings
as public constructs.

CREATE OR REPLACE PACKAGE job_pkg IS


PROCEDURE add_job (jobid jobs.job_id%TYPE, jobtitle jobs.job_title%TYPE);
PROCEDURE del_job (jobid jobs.job_id%TYPE);
FUNCTION get_job (jobid IN jobs.job_id%type) RETURN jobs.job_title%type;
PROCEDURE upd_job(jobid IN jobs.job_id%TYPE, jobtitle IN jobs.job_title%TYPE);
END job_pkg;
/

b.Create the package body with the implementations for each of the subprograms.

CREATE OR REPLACE PACKAGE BODY job_pkg IS


PROCEDURE add_job (
jobid jobs.job_id%TYPE, jobtitle jobs.job_title%TYPE) IS
BEGIN
INSERT INTO jobs (job_id, job_title) VALUES (jobid, jobtitle);
COMMIT;
END add_job;

PROCEDURE del_job (jobid jobs.job_id%TYPE) IS


BEGIN
DELETE FROM jobs
WHERE job_id = jobid; IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20203, 'No jobs deleted.'); END IF;
END DEL_JOB;

FUNCTION get_job (jobid IN jobs.job_id%type)


RETURN jobs.job_title%type IS title jobs.job_title%type;
BEGIN
SELECT job_title INTO title
FROM jobs
WHERE job_id = jobid; RETURN title;
END get_job;

PROCEDURE upd_job(
jobid IN jobs.job_id%TYPE,
jobtitle IN jobs.job_title%TYPE) IS BEGIN
UPDATE jobs
SET job_title = jobtitle WHERE job_id = jobid;
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20202, 'No job updated.'); END IF;
END upd_job;

END job_pkg;
/

c.Invoke your ADD_JOB package procedure by passing the values IT_SYSAN and
Systems Analyst as parameters.

EXECUTE job_pkg.add_job('IT_SYSAN', 'Systems Analyst')

d.Query the JOBS table to see the result.

SELECT * FROM jobs


where job_id='IT_SYSAN';

2.Create and invoke a package that contains private and public constructs.

a.Create a package specification and package body called EMP_PKG that contains your
ADD_EMPLOYEE and GET_EMPLOYEE procedures as public constructs, and include your
VALID_DEPTID function as a private construct.
Package specification:

CREATE OR REPLACE PACKAGE emp_pkg IS


PROCEDURE add_employee(
first_name employees.first_name%TYPE, last_name employees.last_name%TYPE, email
employees.email%TYPE,
job employees.job_id%TYPE DEFAULT 'SA_REP', mgr employees.manager_id%TYPE DEFAULT
145, sal employees.salary%TYPE DEFAULT 1000,
comm employees.commission_pct%TYPE DEFAULT 0, deptid employees.department_id%TYPE
DEFAULT 30);
PROCEDURE get_employee(
empid IN employees.employee_id%TYPE, sal OUT employees.salary%TYPE,
job OUT employees.job_id%TYPE);
END emp_pkg;
/

Package body:

PROCEDURE add_employee(
first_name employees.first_name%TYPE, last_name employees.last_name%TYPE, email
employees.email%TYPE,
job employees.job_id%TYPE DEFAULT 'SA_REP', mgr employees.manager_id%TYPE DEFAULT
145, sal employees.salary%TYPE DEFAULT 1000,
comm employees.commission_pct%TYPE DEFAULT 0, deptid employees.department_id%TYPE
DEFAULT 30) IS
BEGIN
IF valid_deptid(deptid) THEN
INSERT INTO employees(employee_id, first_name, last_name, email,
job_id,manager_id,hire_date,salary,commission_pct,department_id)
VALUES (employees_seq.NEXTVAL, first_name, last_name, email, job, mgr,
TRUNC(SYSDATE), sal, comm, deptid);
ELSE
RAISE_APPLICATION_ERROR (-20204,
'Invalid department ID. Try again.');
END IF;
END add_employee;

PROCEDURE get_employee(
empid IN employees.employee_id%TYPE, sal OUT employees.salary%TYPE,
job OUT employees.job_id%TYPE) IS BEGIN
SELECT salary, job_id INTO sal, job
FROM employees
WHERE employee_id = empid; END get_employee;
END emp_pkg;
/

b.Invoke the EMP_PKG.GET_EMPLOYEE procedure, using department ID 15 for employee


Jane Harris with e-mail JAHARRIS. Because department ID 15 does not exist, you
should get an error message as specified in the exception handler of your
procedure.

EXECUTE emp_pkg.add_employee('Jane', 'Harris','JAHARRIS', deptid => 15)

BEGIN
emp_pkg.add_employee('Jane', 'Harris','JAHARRIS', deptid => 15);
END;

c.Invoke the GET_EMPLOYEE package procedure by using department ID 80 for employee


David Smith with e-mail DASMITH.

EXECUTE emp_pkg.add_employee('David','Smith','DASMITH',deptid=>80)

--PRACTICE-10
1) The rows in the JOBS table store a minimum salary and a maximum salary allowed
for different JOB_ID values. You are asked to write code to ensure that employees’
salaries fall within the range allowed for their job type, for insert and update
operations.

a.Write a procedure called CHECK_SALARY that accepts two parameters, one for an
employee’s job ID string and the other for the salary. The procedure uses the job
ID to determine the minimum and maximum salary for the specified job. If the salary
parameter does not fall within the salary range of the job, inclusive of the
minimum and maximum, then it should raise an application exception, with the
message Invalid salary <sal>. Salaries for job <jobid> must be between
<min> and <max>. Replace the various items in the message with values supplied by
parameters and variables populated by queries. Save the file.
b.Create a trigger called CHECK_SALARY_TRG on the EMPLOYEES table that fires before
an INSERT or UPDATE operation on each row. The trigger must call the CHECK_SALARY
procedure to carry out the business logic. The trigger should pass the new job ID
and salary to the procedure parameters.

CREATE OR REPLACE PROCEDURE check_salary (the_job VARCHAR2, the_salary NUMBER) IS


minsal jobs.min_salary%type; maxsal jobs.max_salary%type;
BEGIN
SELECT min_salary, max_salary INTO minsal, maxsal FROM jobs
WHERE job_id = UPPER(the_job);
IF the_salary NOT BETWEEN minsal AND maxsal THEN RAISE_APPLICATION_ERROR(-20100,
'Invalid salary $'||the_salary||'. '|| 'Salaries for job '|| the_job ||
' must be between $'|| minsal ||' and $' || maxsal); END IF;
END;
/
CREATE OR REPLACE TRIGGER check_salary_trg BEFORE INSERT OR UPDATE OF job_id,
salary ON employees
FOR EACH ROW BEGIN
check_salary(:new.job_id, :new.salary);
END;
/

2) Test the CHECK_SAL_TRG using the following cases:

a.Using your EMP_PKG.ADD_EMPLOYEE procedure, add employee Eleanor Beh in department


30. What happens and why?

EXECUTE emp_pkg.add_employee('Eleanor', 'Beh', 30)

BEGIN
emp_pkg.add_employee('Eleanor', 'Beh', 30);
END;

b.Update the salary of employee 115 to $2,000. In a separate update operation,


change the employee job ID to HR_REP. What happens in each case?
c.Update the salary of employee 115 to $2,800. What happens?

UPDATE employees
SET salary = 2000
WHERE employee_id = 115;

UPDATE employees
SET job_id = 'HR_REP'
WHERE employee_id = 115;

UPDATE employees
SET salary = 2800
WHERE employee_id = 115;

3) Update the CHECK_SALARY_TRG trigger to fire only when the job ID or salary
values have actually changed.

a.Implement the business rule using a WHEN clause to check whether the JOB_ID or
SALARY values have changed.
Note: Make sure that the condition handles the NULL in the OLD.column_name
values if an INSERT operation is performed; otherwise, an insert operation will
fail.

CREATE OR REPLACE TRIGGER check_salary_trg BEFORE INSERT OR UPDATE OF job_id,


salary ON employees FOR EACH ROW
WHEN (new.job_id <> NVL(old.job_id,'?') OR new.salary <> NVL(old.salary,0))
BEGIN
check_salary(:new.job_id, :new.salary);
END;

b.Test the trigger by executing EMP_PKG.ADD_EMPLOYEE procedure with the following


parameter values: first_name='Eleanor', last name='Beh', email='EBEH',
job='IT_PROG', sal=5000.

BEGIN
emp_pkg.add_employee('Eleanor', 'Beh', 'EBEH',
job => 'IT_PROG', sal => 5000);
END;
/

c.Update employees with the IT_PROG job by incrementing their salary by $2,000.
What happens?

UPDATE employees
SET salary = salary + 2000
WHERE job_id = 'IT_PROG';

d.Update the salary to $9,000 for Eleanor Beh.


Hint: Use an UPDATE statement with a subquery in the WHERE clause. What happens?

UPDATE employees
SET salary = 9000
WHERE employee_id = (SELECT employee_id
FROM employees
WHERE last_name = 'Beh');
e.Change the job of Eleanor Beh to ST_MAN using another UPDATE statement with a
subquery. What happens?

UPDATE employees
set job_id = 'ST_MAN'
WHERE employee_id = (SELECT employee_id
FROM employees
WHERE last_name = 'Beh');

4) You are asked to prevent employees from being deleted during business hours.

a.Write a statement trigger called DELETE_EMP_TRG on the EMPLOYEES table to prevent


rows from being deleted during weekday business hours, which are from 9:00 a.m. to
6:00 p.m.

CREATE OR REPLACE TRIGGER delete_emp_trg BEFORE DELETE ON employees


DECLARE
the_day VARCHAR2(3) := TO_CHAR(SYSDATE, 'DY');
the_hour PLS_INTEGER := TO_NUMBER(TO_CHAR(SYSDATE, 'HH24')); BEGIN
IF (the_hour BETWEEN 9 AND 18) AND (the_day NOT IN ('SAT','SUN')) THEN
RAISE_APPLICATION_ERROR(-20150,
'Employee records cannot be deleted during the week 9am and 6pm'); END IF;
END;
/

b.Attempt to delete employees with JOB_ID of SA_REP who are not assigned to a
department.
Note: This is employee Grant with ID 178.

DELETE FROM employees


WHERE job_id = 'SA_REP'
AND department_id IS NULL;

You might also like