REPLACE procedure on oracle 12c - sql

When selecting the employee name and salary of 1500 if there is 1 employee, insert into tMessage the employee's name and the salary amount. If there are 2 or more employees, insert multiple lines. If there are no employees then insert into tMessage without any staff.
create or REPLACE procedure temployees_i(
v_aempname in tregions.aregid%type,
v_aempsal number(3):=1500),
)
is
BEGIN
select lastname,salary from employees ;
EXCEPTION
WHEN SALARY=v_aempsal THEN
insert into tMessage values ('have qualified staff'|| lastname ||'of' salary);
WHEN SALARY!=v_aempsal THEN
insert into tMessage values ('There are no employees
');
END;

I think that's you want.
CREATE OR REPLACE PROCEDURE temployees_i( v_aempsal number := 1500 )
IS
TYPE emprec IS RECORD (empname VARCHAR2(50), salary NUMBER(9,2));
TYPE emp_tab IS TABLE OF emprec;
empv emp_tab;
BEGIN
SELECT lastname, salary bulk COLLECT INTO empv from employees WHERE
SALARY = v_aempsal ;
IF empv.count != 0 then
FORALL i in 1..empv.COUNT
insert into tMessage values ('have qualified staff '||
empv(i).empname ||'of ' ||empv(i).salary);
ELSE
INSERT INTO tMessage VALUES ('There are no employee');
END IF;
COMMIT;
END;

Related

Why am I getting error in trigger when I update salary of employee?

create or replace TRIGGER CHECK_GRADE
BEFORE INSERT OR UPDATE ON EMPLOYEE
FOR EACH ROW
DECLARE
LoSal NUMBER(8, 2);
HiSal NUMBER(8, 2);
Letter VARCHAR(1);
Sal NUMBER(8, 2);
BEGIN
IF(:NEW.GLetter IS NOT NULL)
THEN
Sal := NVL(:NEW.Salary, -1);
SELECT MinSalary, MaxSalary
INTO LoSal, HiSal
FROM GRADE
WHERE GLetter = :NEW.GLetter;
IF(NOT(Sal BETWEEN LoSal AND HiSal))
THEN
RAISE_APPLICATION_ERROR(-20001, 'Salary does not correspond to grade error! ' );
END IF;
ELSIF(:NEW.Salary IS NOT NULL)
THEN
SELECT GLetter
INTO Letter
FROM GRADE
WHERE :NEW.Salary BETWEEN MinSalary AND MaxSalary;
:NEW.GLetter := Letter;
END IF;
END;
This is the sql statement I run
basically what I want to do is that when a user tries to update the salary of an employee the trigger will automatically fill the grade of the employee which corresponds to his/her salary
update employee set salary = 25500 where employeeid = 1006;
Table for employee
has attributes like name department name and others and salary and grade
Table for Grade has
minsalary
max salary
gradeletter
Error starting at line : 2 in command -
update employee set salary = 25500 where employeeid = 1006
Error report -
ORA-20001: Salary does not correspond to grade error!
ORA-06512: at "gh12345.CHECK_GRADE", line 18
ORA-04088: error during execution of trigger 'gh12345.CHECK_GRADE'
The error is being raised because of this part here:
SELECT MinSalary, MaxSalary
INTO LoSal, HiSal
FROM GRADE
WHERE GLetter = :NEW.GLetter;
IF(NOT(Sal BETWEEN LoSal AND HiSal))
THEN
RAISE_APPLICATION_ERROR(-20001, 'Salary does not correspond to grade error! ' );
END IF;
you are setting the salary to the value 25500 which is out of the range defined in this table GRADE.
So you should do a query on this table and define a value for Salary that is within this range, or update the GRADE table for your new disired range.

Table not updating when trigger is fired

I have 2 tables:
Employees(Employee_ID, First_name, Last_name, Email, Hire_date, Department_ID)
Departments(Department_ID, Department_name, Total_employees).
I have created trigger that fires after inserting an employee to employees table. It increases the total_employees column by 1 for :new inserted Department_ID.
Trigger:
create or replace TRIGGER emp_count_department
AFTER INSERT OR DELETE ON EMPLOYEES
for each row
DECLARE
counter NUMBER;
BEGIN
if inserting then
select total_employees into counter
from departments
where department_id = :new.department_id;
update departments
set total_employees = counter+1
where department_id = :new.department_id;
elsif deleting then
select total_employees into counter
from departments
where department_id = :old.department_id;
update departments
set total_employees = counter-1
where department_id = :old.department_id;
end if;
END;
When I try to insert an employee, it is inserted but it doesn't increase total_employees by 1 in departments table. When I try to insert an employee with a department_ID that doesn't exist in departments table, it gives me error. So the trigger is working but not increasing the total numbers by 1.
Try this:
create or replace TRIGGER emp_count_department
AFTER INSERT OR DELETE ON EMPLOYEES
for each row
BEGIN
if inserting then
update departments
set total_employees = total_employees+1
where department_id = :new.department_id;
elsif deleting then
update departments
set total_employees = total_employees-1
where department_id = :old.department_id;
end if;
END;
I did simple testing of your code in Oracle 11g and it seems to work.
Please check if you missed in adding information.
create table emp1(emp_id number ,dept_id number);
create table dept1 (dept_id number ,total_emp number);
CREATE OR replace TRIGGER emp_count_dept
AFTER INSERT OR DELETE ON emp1
FOR EACH ROW
DECLARE
counter NUMBER;
BEGIN
IF inserting THEN
UPDATE dept1
SET total_emp = total_emp + 1
WHERE dept_id = :new.dept_id;
ELSIF deleting THEN
UPDATE dept1
SET total_emp = total_emp - 1
WHERE dept_id = :old.dept_id;
END IF;
END;
insert into dept1 values(10,10);
insert into emp1 values(10,10);
select * from dept1;
DEPT_ID TOTAL_EMP
10 11
I think you are missing an important use case, what if the employees table is updated and the dept_id changes. To expand upon the answer #pmdba gave, I think the following code would work best.
CREATE OR REPLACE TRIGGER emp_count_dept
AFTER INSERT OR UPDATE OF DEPT_ID OR DELETE ON employees
FOR EACH ROW
BEGIN
IF :new.dept_id IS NOT NULL THEN
UPDATE departments d
SET d.total_employees = NVL(d.total_employees, 0)+1
WHERE d.department_id = :new.dept_id;
END IF;
IF :old.dept_id IS NOT NULL THEN
UPDATE departments d
SET d.total_employees = d.total_employees - 1
WHERE d.department_id = :old.dept_id;
END IF;
END;
/
This takes care of UPDATE statements now. And also takes care of the first INSERT for a given department (If you didn't initialize all departments.total_employee to 0 when you created them).
I also created this DBFiddle demonstrating the functionality (And why you need the NVL function or to default your TOTAL_EMPLOYEES column to 0) (Link)

Triggers in PL-SQL

I have two tables:
create table speciality(
major varchar2(30),
total_credits number,
total_students number);
create table students(
id number(5) primary key,
first_name varchar2(20),
last_name varchar2(20),
major varchar2(30),
current_credits number(3));
I want to create a trigger that carries the name UpdateSpeciality that deletes, updates and inserts into speciality table right when the same operation happens on students table.
This is how the speciality table should look after the following:
SQL> INSERT INTO STUDENTS(id, first_name, last_name, major, current_credits) values(10001, 'sam', 'ali', 'computer science', 11);
SQL>INSERT INTO STUDENTS(id, first_name, last_name, major, current_credits) values(10002, 'kevin', 'mark', 'MIS', 4);
SQL>INSERT INTO STUDENTS(id, first_name, last_name, major, current_credits) values(10003, 'robert', 'jack', 'computer science', 8);
How can I solve this? I don't know how to connect the two tables.
Should I use stored procedures?
CREATE OR REPLACE TRIGGER UpdateSpeciality
after insert or delete or update on students
for each row
begin
if inserting /* this is how far i got */
Something like this should do it. With some assumtions :)
CREATE OR REPLACE TRIGGER UpdateSpeciality
after insert or delete or update on students
for each row
declare
cursor c_spec(sMajor speciality.major%type) is
select * from speciality
where major = sMajor
for update;
r_spec c_spec%ROWTYPE;
begin
if inserting then
open c_spec(:new.major);
fetch c_spec into r_spec;
if c_spec%FOUND then
update speciality set
total_credits = total_credits + :new.current_credits,
total_students = total_students + 1
where current of c_spec;
else
insert into speciality(major, total_credits, total_students) values (:new.major, :new.current_credits, 1);
end if;
close c_spec;
elsif updating then
open c_spec(:new.major);
fetch c_spec into r_spec;
if c_spec%FOUND then
update speciality set
total_credits = total_credits + :new.current_credits - :old.current_credits
where current of c_spec;
else
insert into speciality(major, total_credits, total_students) values (:new.major, :new.current_credits, 1);
end if;
close c_spec;
elsif deleting then
open c_spec(:old.major);
fetch c_spec into r_spec;
if c_spec%FOUND then
update speciality set
total_credits = total_credits - :old.current_credits ,
total_students = total_students - 1
where current of c_spec;
if r_spec.total_students = 1 then
delete from speciality where major = :old.major;
end if;
end if;
close c_spec;
end if;
end;

associative arrays and loops

I need to select employees with employee_id from 100 to 110, loop through emp table and add 10% to each emp_salary, then display results from the emp table
DECLARE
vname VARCHAR(100);
TYPE emp_table_type is TABLE OF employees.last_name%TYPE
INDEX BY PLS_INTEGER;
vname_table emp_table_type;
BEGIN
for i in 100..110
SELECT last_name into vname from employees where employee_id = i;
end loop;
vname_table(1) := vname;
DBMS_OUTPUT.PUT_LINE(vname_table(1));
End;
I need to select employees with employee_id from 100 to 110, loop
through emp table and add 10% to each emp_salary, then display results
from the emp table
You can do it as :
DECLARE
sal NUMBER;
TYPE emp_table_type IS TABLE OF employee.employee_id%TYPE
INDEX BY PLS_INTEGER;
vname_table emp_table_type;
BEGIN
---Selecting employee
SELECT employee_id
BULK COLLECT INTO vname_table
FROM employee
WHERE employee_id BETWEEN 100 AND 110;
FOR i IN 1 .. vname_table.LAST
LOOP
--- Updating Salary
UPDATE Employee
SET salary = salary + (salary * 0.10)
WHERE employee_id = vname_table (i)
RETURNING salary
INTO sal;
--- Displaying updated salary
DBMS_OUTPUT.PUT_LINE (sal);
END LOOP;
END;

Check if there is a location_id and manager_id with the same name (they are from different tables)

So on that code I checked the uniqueness of department_id and department_name. Now I would like to do the same with manager_id and locations_id. Please keep in mind that manager_id is from table EMPLOYEES and locations_id is from table LOCATIONS.
I wonder if I can just continue that statement:
upper(s.department_id) = upper(d.department_id)
OR upper(s.department_name) = upper(d.department_name)
But I think that will not be enough, because it will check only in the DEPARTMENTS table. Not from LOCATIONS and EMPLOYEES like I want. Please advise.
CREATE OR REPLACE PROCEDURE add_dep(p_id NUMBER,
p_name VARCHAR2,
p_mgr NUMBER,
p_loc NUMBER) IS
BEGIN
MERGE INTO departments d
USING (
SELECT
p_id department_id,
p_name department_name,
p_mgr manager_id,
p_loc location_id
FROM dual) s
ON ( upper(s.department_id) = upper(d.department_id)
OR upper(s.department_name) = upper(d.department_name))
WHEN NOT MATCHED THEN
INSERT VALUES (s.department_id, s.department_name, s.manager_id, s.location_id);
IF SQL%ROWCOUNT = 0 THEN
INSERT INTO error_depa VALUES (p_id, p_name, p_mgr, p_loc);
END IF;
END;
EDIT - additional information
I got an error that there are not enough values for LOCATIONS and EMPLOYEES table. But I also tried to make this with exception and no_data_found. Can you modify this code and help me with that please? I would like to check the same for locations_id and manager_id.
create or replace procedure add_de(
p_id NUMBER,
p_name VARCHAR2,
p_mgr NUMBER,
p_loc NUMBER
)
is
v_dummy number;
begin
select 1
into v_dummy
from departments
where department_name = p_name OR DEPARTMENT_ID = p_id ;
insert
into error_depa
values(
p_id,
p_name,
p_mgr,
p_loc
);
exception
when no_data_found
then
insert
into departments
values(
p_id,
upper(p_name),
p_mgr,
p_loc
);
end;
I think that you want something like this:
CREATE OR REPLACE PROCEDURE add_dep(p_id NUMBER,
p_name VARCHAR2,
p_mgr NUMBER,
p_loc NUMBER) IS
BEGIN
MERGE INTO departments d
USING (
SELECT
p_id department_id,
p_name department_name,
p_mgr manager_id,
p_loc location_id
FROM dual) s
ON ( upper(s.department_id) = upper(d.department_id)
OR upper(s.department_name) = upper(d.department_name))
WHEN NOT MATCHED THEN
***INSERT(department_id, department_name,manager_id,location_id)*** VALUES (s.department_id, s.department_name, s.manager_id, s.location_id);
COMMIT;
MERGE INTO employees trg
USING (
SELECT
*
FROM employees
where
manager_id = p_mgr) src
ON ( upper(trg.manager_id) = upper(src.manager_id))
WHEN NOT MATCHED THEN
***INSERT(department_id, ...)*** VALUES (src.department_id, ....);
COMMIT;
MERGE INTO locations trg
USING (
SELECT
*
FROM locations
where
locations_id = p_loc) src
ON ( upper(trg.locations_id) = upper(src.locations_id))
WHEN NOT MATCHED THEN
***INSERT(locations_id, ...)*** VALUES (src.locations_id, ....);
COMMIT;
IF SQL%ROWCOUNT = 0 THEN
INSERT INTO error_depa VALUES (p_id, p_name, p_mgr, p_loc);
END IF;
END;
/