oracle package and trigger - oracle

Create a database that contains four tables department, employee,
address and contact info, then Store 5 Records in each table.
Write the PL/SQL Statement for the following:
Store a record into employee, address and contact using trigger.
Retrieve departments and their employees using package
..........................
this is my code , what am i doing wrong ?
-- Question 2 :
-- Create Tables :
CREATE TABLE address (
code int primary key,
city varchar2(30),
street varchar2(30)
);
create table Department (
DepId int primary key ,
Dep_Name varchar2(30) ,
Dep_adress varchar(30));
create table Employee (
Emp_Id int primary key ,
firstName varchar2(30),
lastName varchar2(30),
salary int,
Dep_Id int references Department (DepId),
AdCode int references address (code));
CREATE TABLE contact_info (
email varchar2(30) primary key ,
phone int ,
EmpId int references Employee (Emp_Id));
-- insert :
insert into Department values (1,'IT','Amman');
insert into Department values (2,'CS','Jerash');
insert into Department values (3,'accounting','Amman');
insert into Department values (4,'managment','Amman');
insert into Department values (5,'employment','Amman');
insert into address values (50,'Amman','AAA');
insert into address values (60,'Amman','AAB');
insert into address values (70,'Amman','AAC');
insert into address values (80,'Jerash','AAD');
insert into address values (90,'Irbid','AAE');
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (1,'john' , 'samo' , 1000 , (select DepId from Department where Dep_Name = 'IT'),(select code from address where street = 'AAA'));
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (2,'mark' , 'wol' , 2000 , (select DepId from Department where Dep_Name = 'IT'),(select code from address where street = 'AAB'));
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (3,'ahmad' , 'moh' , 1100 , (select DepId from Department where Dep_Name = 'IT'),(select code from address where street = 'AAC'));
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (4,'maher' , 'imk' , 1700 , (select DepId from Department where Dep_Name = 'CS'),(select code from address where street = 'AAD'));
insert into Employee (Emp_Id,firstName,lastName,salary,Dep_Id,AdCode) values (5,'ali' , 'geh' , 1200 , (select DepId from Department where Dep_Name = 'CS'),(select code from address where street = 'AAE'));
insert into contact_info values ('john#gmail.com',0785602200, (select Emp_Id from Employee where salary = 1000));
insert into contact_info values ('mark#gmail.com',0785602201, (select Emp_Id from Employee where salary = 2000));
insert into contact_info values ('ahmad#gmail.com',0785602202, (select Emp_Id from Employee where salary = 1100));
insert into contact_info values ('maher#gmail.com',0785602203, (select Emp_Id from Employee where salary = 1700));
insert into contact_info values ('ali#gmail.com',0785602204, (select Emp_Id from Employee where salary = 1200));
-- trigger :
CREATE OR REPLACE TRIGGER add_rec
AFTER INSERT
ON Department
FOR EACH ROW
DECLARE
Empl_id NUMBER;
BEGIN
INSERT INTO address(code,city,street)
VALUES(:NEW.code, :NEW.city, :NEW.street)
INSERT INTO contact_info(email, phone, EmpId)
VALUES(:NEW.email, :NEW.phone, :NEW.EmpId)
INSERT INTO Employee(Emp_Id,firstName,lastName,salary,Dep_Id,AdCode)
VALUES(:NEW.Emp_Id, :NEW.firstName, :NEW.lastName, :NEW.salary, :NEW.lastName, :NEW.Dep_Id, :NEW.AdCode)
END;
-- Package :
set serveroutput on;
CREATE OR REPLACE PACKAGE emp_dept AS
TYPE EmpDept IS RECORD (employee_id number , last_name varchar2(25) , department_id number);
CURSOR dept_employees RETURN EmpDept;
PROCEDURE department_employee;
END emp_dept;
/
CREATE OR REPLACE PACKAGE BODY emp_dept AS
CURSOR dept_employees RETURN EmpDept is (select employee_id , last_name , d.department_id from Employee e join Department d on e.department_id = d.department_id);
rec EmpDept;
PROCEDURE department_employee
is
begin
open dept_employees;
loop
fetch dept_employees into rec;
exit when dept_employees%notfound;
dbms_output.put_line(rpad(rec.employee_id,5,' ') ||rpad(rec.last_name,12,' ') || rec.department_id);
end loop;
end;
END emp_dept;
/
execute EMP_DEPT.DEPARTMENT_EMPLOYEE;

As of package, when you fix errors (wrong column names), it compiles and returns result:
SQL> CREATE OR REPLACE PACKAGE emp_dept AS
2 TYPE empdept IS RECORD (
3 employee_id NUMBER,
4 last_name VARCHAR2(25),
5 department_id NUMBER
6 );
7 CURSOR dept_employees RETURN empdept;
8 PROCEDURE department_employee;
9
10 END emp_dept;
11 /
Package created.
SQL> CREATE OR REPLACE PACKAGE BODY emp_dept AS
2
3 CURSOR dept_employees RETURN empdept IS
4 ( SELECT
5 emp_id,
6 lastname,
7 d.depid
8 FROM
9 employee e
10 JOIN department d ON e.dep_id = d.depid
11 );
12
13 rec empdept;
14
15 PROCEDURE department_employee IS
16 BEGIN
17 OPEN dept_employees;
18 LOOP
19 FETCH dept_employees INTO rec;
20 EXIT WHEN dept_employees%notfound;
21 dbms_output.put_line(rpad(rec.employee_id, 5, ' ')
22 || rpad(rec.last_name, 12, ' ')
23 || rec.department_id);
24
25 END LOOP;
26
27 END;
28
29 END emp_dept;
30 /
Package body created.
Testing:
SQL> EXECUTE emp_dept.department_employee;
1 samo 1
2 wol 1
3 moh 1
4 imk 2
5 geh 2
PL/SQL procedure successfully completed.
SQL>
As of trigger: that question/requirement doesn't make any sense. How would you enter rows into all those tables, based on 3 columns you enter into the department table? You just don't have any values to insert ... From my point of view, either you misinterpreted the problem, or it can't be done as you described it.

Related

Trigger DML in oracle database

I have problem with my dml trigger on oracle database.I want to launch trigger when i update first_name or last name on employees table in hr schema. During execution trigger i Have error ORA-00060: Please help. Idon't have any ideas how can i fix it.enter image description here
CREATE OR replace TRIGGER up_sal
BEFORE UPDATE OF first_name, last_name ON employees
FOR EACH ROW
DECLARE
PRAGMA autonomous_transaction;
var_sal employees.salary%TYPE;
var_avg NUMBER;
var_emp_id NUMBER;
BEGIN
SELECT salary
INTO var_sal
FROM employees
WHERE first_name = :NEW.first_name
OR last_name = :NEW.last_name;
SELECT Avg(salary)
INTO var_avg
FROM employees
WHERE department_id IN( :OLD.department_id );
IF var_sal < var_avg THEN
var_emp_id := :OLD.employee_id;
UPDATE employees
SET salary = var_avg * 1.1
WHERE employee_id = var_emp_id;
COMMIT;
END IF;
END;
You can use:
CREATE TRIGGER up_sal
BEFORE UPDATE OF first_name, last_name ON employees
FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
var_avg employees.salary%TYPE;
BEGIN
SELECT Avg(salary)
INTO var_avg
FROM employees
WHERE department_id IN( :OLD.department_id );
IF :NEW.salary < var_avg THEN
:NEW.salary := var_avg * 1.1;
END IF;
COMMIT;
END;
/
Which, for the sample data:
CREATE TABLE employees (
department_id NUMBER,
first_name VARCHAR2(20),
last_name VARCHAR2(20),
salary NUMBER
);
INSERT INTO employees (department_id, first_name, last_name, salary)
SELECT 1, 'Alice', 'Abbot', 90 FROM DUAL UNION ALL
SELECT 1, 'Betty', 'Baron', 95 FROM DUAL UNION ALL
SELECT 1, 'Carol', 'Count', 105 FROM DUAL UNION ALL
SELECT 1, 'Debra', 'Duke', 110 FROM DUAL;
Then if you do:
UPDATE employees
SET first_name = TRIM(first_name),
last_name = TRIM(last_name);
Then:
SELECT * FROM employees;
Outputs:
DEPARTMENT_ID
FIRST_NAME
LAST_NAME
SALARY
1
Alice
Abbot
110
1
Betty
Baron
110
1
Carol
Count
105
1
Debra
Duke
110
db<>fiddle here

Display the employee detail with department name of given Fname if he is accountant

input from
tblemp(empid number primary key,
fname varchar2(20),
lname varchar2(20),
jdate date, salary number,
mid number,
post varchar2(20),
did varchar2(10) references tbldept1 (did)) ;
tbldept1(did varchar2(10) primary key,dname varchar2(10));
Write a pl/sql block of code to Display the employee detail with department name of given Fname if he is accountant.
i am try it for two method but still i am get error .
first method in this code by using type function:
declare
type temp is record (
veid tblemp1.empid%type,
vfname tblemp1.fname%type,
vlname tblemp1.lname%type,
vsalary tblemp1.salary%type,
vmid tblemp1.mid%type,
vjdate tblemp1.jdate%type,
vpost tblemp1.post%type,
vdid tblemp1.did%type,
vdname tbldept.dname%type);
remp temp;
remp1 temp;
begin
select empid,fname,lname,salary,mid,jdate,post,d.did,dname into remp from tblemp1 e,tbldept d where e.did=d.did and empid=&empid;
select empid,fname,lname,salary,mid,jdate,post,d.did,dname into remp1 from tblemp1 e,tbldept d where e.did=d.did and e.post='Accountant';
dbms_output.put_line('empid = '||remp.empid);
dbms_output.put_line('fname = '||remp.fname);
dbms_output.put_line('lname = '||remp.lname);
dbms_output.put_line('jdate = '||remp.jdate);
dbms_output.put_line('mid = '||remp.mid);
dbms_output.put_line('post = '||remp.post);
dbms_output.put_line(' did = '||remp.did);
dbms_output.put_line(' salary = '||remp.salary);
dbms_output.put_line(' dname = '||remp1.dname);
end;
/
second method is by using row type function using
declare
remp tblemp1%rowtype;
remp1 tbldept%rowtype;
begin
select * into remp from tblemp1 where empid=&empid and post='Accountant';
select * into remp1 from tbldept ;
dbms_output.put_line('empid = '||remp.empid);
dbms_output.put_line('fname = '||remp.fname);
dbms_output.put_line('lname = '||remp.lname);
dbms_output.put_line('jdate = '||remp.jdate);
dbms_output.put_line('mid = '||remp.mid);
dbms_output.put_line('post = '||remp.post);
dbms_output.put_line(' did = '||remp.did);
dbms_output.put_line(' salary = '||remp.salary);
dbms_output.put_line(' dname = '||remp1.dname);
end;
/
i am try it with two method .
im try it till morning but untill i am not getting output.
my prectical exam pass come so plaese help me.
I wasn't sure if your table names were correct (your code didn't match your question text), but if you fix them, then your code looks reasonable to me
SQL> create table tbldept1(did varchar2(10) primary key,dname varchar2(10));
Table created.
SQL>
SQL> create table tblemp(empid number primary key, fname varchar2(20), lname varchar2(20),
2 jdate date, salary number, mid number, post varchar2(20), did varchar2(10) references tbldept1 (did)) ;
Table created.
SQL>
SQL> insert into tbldept1 values (10,'Accounts');
1 row created.
SQL> insert into tblemp values (1000,'Jane','Doe',sysdate,1000,1001,'Accountant',10);
1 row created.
SQL>
SQL>
SQL> set serverout on
SQL> declare
2 remp tblemp%rowtype;
3 remp1 tbldept1%rowtype;
4
5 begin
6 select * into remp from tblemp where empid=&empid and post='Accountant';
7
8 select * into remp1 from tbldept1 ;
9
10 dbms_output.put_line('empid = '||remp.empid);
11 dbms_output.put_line('fname = '||remp.fname);
12 dbms_output.put_line('lname = '||remp.lname);
13 dbms_output.put_line('jdate = '||remp.jdate);
14 dbms_output.put_line('mid = '||remp.mid);
15 dbms_output.put_line('post = '||remp.post);
16 dbms_output.put_line(' did = '||remp.did);
17 dbms_output.put_line(' salary = '||remp.salary);
18 dbms_output.put_line(' dname = '||remp1.dname);
19
20 end;
21 /
Enter value for empid: 1000
old 6: select * into remp from tblemp where empid=&empid and post='Accountant';
new 6: select * into remp from tblemp where empid=1000 and post='Accountant';
empid = 1000
fname = Jane
lname = Doe
jdate = 22-MAR-22
mid = 1001
post = Accountant
did = 10
salary = 1000
dname = Accounts
PL/SQL procedure successfully completed.

Procedure to delete employee records from employee table

Create a procedure that deletes employee records from the Employee table. Get the department name as an input parameter. Delete the employee records who belongs to that department.
Display the count of employee records that were deleted. If the respective department was not found, then raise "DeptNotFoundException" and print the message 'No Records found.'
Assume the Employee table has been already created and a few records have been inserted.
EMPLOYEE:
Column name Data type Constraints
EMP_ID NUMBER(5) PK
EMP_NAME VARCHAR2(25) NOT NULL
SALARY NUMBER(10,2)
DEPT VARCHAR2(25)
EMP_ID EMP_NAME SALARY DEPT
------ -------- ------- -----
101 Tom 54000 MECH
102 William 43000 CSE
103 John 34560 MECH
104 Smith 56000 CSE
105 Steve 23450 IT
Functional Requirements:
PROCEDURE DELETE_EMPLOYEE( v_dept IN EMPLOYEE.dept%TYPE)
Sample Output:
2 Employee record(s) got deleted.
(Hint: Data is case sensitive. Use '/' to terminate the PLSQL block)
I have tried to solve this using my own logic, but it is showing error(out of 2 test only one is passed) can anyone point out the mistake?
set serveroutput on;
create or replace PROCEDURE DELETE_EMPLOYEE(v_dept IN EMPLOYEE.dept%TYPE)
is
temp number;
DEPTNOTFOUNDEXCEPTION Exception;
begin
select count(dept) into temp from EMPLOYEE where dept=v_dept;
delete from EMPLOYEE where dept=v_dept;
if temp>=1 then
dbms_output.put_line(temp||' Employee record(s) got deleted.');
else
raise DEPTNOTFOUNDEXCEPTION;
end if;
exception
when DEPTNOTFOUNDEXCEPTION then
dbms_output.put_line('No Records Found.');
end;
/
As others have pointed out, you can use SQL%ROWCOUNT and generally tidy up a bit but it doesn't look "wrong".
CREATE TABLE employee (
emp_id NUMBER(5) PRIMARY KEY
, emp_name VARCHAR2(25) NOT NULL
, salary NUMBER(10,2)
, dept VARCHAR2(25)
);
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (101, 'Tom', 54000, 'MECH');
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (102, 'William', 43000, 'CSE');
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (103, 'John', 34560, 'MECH');
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (104, 'Smith', 56000, 'CSE');
INSERT INTO employee (emp_id, emp_name, salary, dept) VALUES (105, 'Steve', 23450, 'IT');
DECLARE
dept_not_found EXCEPTION;
PROCEDURE delete_employee (p_dept IN employee.dept%TYPE) IS
BEGIN
DELETE employee
WHERE dept = p_dept;
IF SQL%ROWCOUNT = 0 THEN
RAISE dept_not_found;
END IF;
dbms_output.put_line(SQL%ROWCOUNT||' Employee record(s) got deleted.');
END delete_employee;
BEGIN
delete_employee('CSE');
delete_employee('ZZZ');
EXCEPTION
WHEN dept_not_found THEN
dbms_output.put_line('No Records Found.');
END;
/
2 Employee record(s) got deleted.
No Records Found.
PL/SQL procedure successfully completed.
Only an advice: Stop using raise when you want to output something. raise have always much more workload than:
if (sql%rowcount = 0) then
DBMS_Output.Put_Line('No Record Found');
return;
end if;

Writing a procedure with an array as out parameter

I can't create a PL/SQL stored procedure. For example returns all of the ename of employees in deptno 20.
create table emp(
empno number(4,0),
ename varchar2(10),
job varchar2(9),
mgr number(4,0),
hiredate date,
sal number(7,2),
comm number(7,2),
deptno number(2,0),
constraint pk_emp primary key (empno),
constraint fk_deptno foreign key (deptno) references dept (deptno)
);
This is what i manage to do but i can't seem to move/write it into a procedure.
declare
TYPE name_array IS TABLE OF emp.ename %type
INDEX BY BINARY_INTEGER;
enames name_array;
begin
update emp set empno = empno where deptno = 20
returning ename bulk collect into enames;
for i in 1..enames.count loop
dbms_output.put_line('ename : '||enames(i));
end loop;
end;
/
When returning a single object (which includes a table of values), I prefer functions over out parameters. Here is code that implements both.
drop table emp purge;
drop table dept purge;
CREATE TABLE dept
(
deptno INTEGER PRIMARY KEY
);
CREATE TABLE emp
(
empno NUMBER (4, 0)
, ename VARCHAR2 (10)
, job VARCHAR2 (9)
, mgr NUMBER (4, 0)
, hiredate DATE
, sal NUMBER (7, 2)
, comm NUMBER (7, 2)
, deptno NUMBER (2, 0)
, CONSTRAINT pk_emp PRIMARY KEY (empno)
, CONSTRAINT fk_deptno FOREIGN KEY (deptno) REFERENCES dept (deptno)
);
CREATE or replace PACKAGE emp_pkg
AS
TYPE name_array_t IS TABLE OF emp.ename%TYPE
INDEX BY BINARY_INTEGER;
FUNCTION upd (p_empno IN emp.empno%TYPE)
RETURN name_array_t;
PROCEDURE upd (
p_empno IN emp.empno%TYPE
, p_names OUT name_array_t
);
END emp_pkg;
CREATE or replace PACKAGE BODY emp_pkg
AS
FUNCTION upd (p_empno IN emp.empno%TYPE)
RETURN name_array_t
AS
l_names name_array_t;
BEGIN
UPDATE emp
SET empno = empno
WHERE deptno = 20
RETURNING ename
BULK COLLECT INTO l_names;
RETURN l_names;
END upd;
PROCEDURE upd (
p_empno IN emp.empno%TYPE
, p_names OUT name_array_t
)
AS
BEGIN
p_names := upd (p_empno);
END upd;
END emp_pkg;
This is a sample Stored Proc with return type as Array
create
procedure sample_proc(p_cust_id in number, p_customers out custarray)
as
my_cust custarray := custarray();

Assigning data in a new table to an existing foreign key in a for loop

I was wondering if there was a way to assign new data in a table to an existing foreign key.
For example if I use the following loop to assign randomly generated numbers to columns in the customer table, how would I be able to link cust_id, which I have assigned as a foreign key in the Sales table, with new data created each time a new sale is made?
CUSTOMER:
DECLARE
v_cust_id NUMBER(4) NOT NULL := 0000;
v_cust_name VARCHAR2(30);
v_cust_add VARCHAR2(30);
v_phone VARCHAR2(10);
BEGIN
FOR v IN 1 .. 2000 --Loop 2000 times to create data for the 2000 customers in the database.
LOOP
v_cust_id := v_cust_id + 1;
v_cust_name := dbms_random.string('U',5);
v_cust_add := dbms_random.string('A',15);
v_phone := dbms_random.value(1000000,9999999);
INSERT INTO customer (cust_id, cust_name, cust_add, phone)
VALUES (v_cust_id, v_cust_name, v_cust_add, v_phone);
END LOOP;
END;
/
SALES:
DECLARE
v_sale_id NUMBER(4) NOT NULL := ;
v_sale_price NUMBER(8,2);
v_sale_date DATE;
v_no_of_prods NUMBER(4);
v_prod_id NUMBER(4);
v_desp_id NUMBER(4);
v_cust_id NUMBER(4);
BEGIN
FOR v IN 1 .. 10
LOOP
v_sale_id :=
v_sale_price
v_sale_date :=
v_no_of_products :=
v_prod_id :=
v_desp_id :=
v_cust_id :=
INSERT INTO sales (sale_id, sale_price, sale_date, no_of_prods, prod_id, desp_id, cust_id)
VALUES (v_sale_id, v_sale_price, v_sale_date, v_no_of_prods, v_prod_id, v_desp_id, v_cust_id);
END LOOP;
END;
\
You are generating test data to do some kind of performance test?
Let's first generate 2000 customers.
(untested)
insert into customer
(cust_id, cust_name, cust_add, phone)
select
level l,
dbms_random.string('U',5),
dbms_random.string('A',15),
dbms_random.value(1000000,9999999)
from dual
connect by level <= 2000;
Now you can genereate sales data by selecting from the customer table:
insert into sales
(sale_id, sale_price, sale_date, no_of_prods, prod_id, desp_id, cust_id)
select sale_id_sequence.nextval , dbms_random. ...., cust_id
from customer;
insert into sales
(sale_id, sale_price, sale_date, no_of_prods, prod_id, desp_id, cust_id)
select sale_id_sequence.nextval , dbms_random. ...., cust_id
from customer
where mod(cust_id,2) =0;
insert into sales
(sale_id, sale_price, sale_date, no_of_prods, prod_id, desp_id, cust_id)
select sale_id_sequence.nextval , dbms_radom. ...., cust_id
from customer
where mod(cust_id,7) =0;
insert into sales
(sale_id, sale_price, sale_date, no_of_prods, prod_id, desp_id, cust_id)
select sale_id_sequence.nextval , dbms_random. ...., cust_id
from customer
where mod(cust_id,13) =0;
commit;
I assume there is a sequence to create a sale id.
edit1 improvement:
create table customer
( cust_id number(10)
, cust_name varchar2(50)
, cust_add varchar2(30)
, cust_phone varchar2(10)
);
create sequence cust_id_seq;
create table sales
( sale_id number(10)
, prod_no number(10)
, cust_id number(10)
);
create sequence sale_id_seq;
begin
insert into customer
select cust_id_seq.nextval
, dbms_random.string('U',5)
, dbms_random.string('A',15)
, trunc(dbms_random.value(1000000,9999999))
from dual
connect by level < 2000;
for i in 1..10 loop
insert into sales
select sale_id_seq.nextval
, trunc(dbms_random.value(1,100))
, cust_id
from customer;
insert into sales
select sale_id_seq.nextval
, trunc(dbms_random.value(1,100))
, cust_id
from customer
where mod(cust_id+i,2)=0;
insert into sales
select sale_id_seq.nextval
, trunc(dbms_random.value(1,100))
, cust_id
from customer
where mod(cust_id+i,7)=0;
end loop;
end;
/
commit;
select count(*) from customer;
select count(*) from sales;

Resources