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)
Related
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;
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.
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;
I created this 4 tables:
create table terminatedEmployees (
empid number primary key,
dept number,
empname varchar2(50),
salary number
);
create table employees (
empid number primary key,
dept number,
empname varchar2(50),
salary number
);
create table payroll (
empid number primary key,
salary number,
CONSTRAINT fk_payemploy
FOREIGN KEY (empid)
REFERENCES employees(empid)
);
create table salaryAudit (
empid number primary key,
oldsal number,
newsal number,
datechanged date,
changedby varchar2(25),
CONSTRAINT fk_salaryaudit
FOREIGN KEY (empid)
REFERENCES employees(empid)
);
and now I'm trying to create a trigger in order to update two of them when employees table is updated:
CREATE TRIGGER trigger_updated_employees
AFTER UPDATE ON employees
FOR EACH ROW
when (old.salary != new.salary)
BEGIN
UPDATE INTO salaryAudit (newsal, oldsal)
VALUES(:new.salary, :old.salary);
UPDATE INTO payroll (salary)
VALUES(:new.salary);
END;
But I'm getting the error:
2/5 PL/SQL: SQL Statement ignored
2/12 PL/SQL: ORA-00903: invalid table name
4/5 PL/SQL: SQL Statement ignored
4/12 PL/SQL: ORA-00903: invalid table name
The three tables I'm calling in the trigger are ok and other triggers I created work...
Try something like this:
CREATE TRIGGER TRIGGER_UPDATED_EMPLOYEES
AFTER UPDATE ON EMPLOYEES
FOR EACH ROW
WHEN (OLD.SALARY <> NEW.SALARY)
BEGIN
MERGE INTO PAYROLL p
USING (SELECT :NEW.EMPID AS EMPID FROM DUAL) d
ON (p.EMPID = d.EMPID)
WHEN NOT MATCHED THEN
INSERT (EMPID, SALARY)
VALUES (:NEW.EMPID, :NEW.SALARY)
WHEN MATCHED THEN
UPDATE
SET SALARY = :NEW.SALARY;
MERGE INTO SALARYAUDIT a
USING (SELECT :NEW.EMPID AS EMPID FROM DUAL) d
ON (a.EMPID = d.EMPID)
WHEN NOT MATCHED THEN
INSERT (EMPID, OLDSAL, NEWSAL, DATECHANGED, CHANGEDBY)
VALUES (:NEW.EMPID, :OLD.SALARY, :NEW.SALARY, SYSDATE, 'SOME_USER')
WHEN MATCHED THEN
UPDATE
SET OLDSAL = :OLD.SALARY,
NEWSAL = :NEW.SALARY,
DATECHANGED = SYSDATE,
CHANGEDBY = 'SOME_USER';
END TRIGGER_UPDATED_EMPLOYEES;
Share and enjoy.
I got it working just correcting the UPDATE statements syntax and modifying the condition as #BobJarvis suggested, this is the final result:
CREATE TRIGGER trigger_updated_employees
AFTER UPDATE OF salary ON employees
FOR EACH ROW
when (old.salary <> new.salary)
BEGIN
UPDATE salaryAudit
SET (newsal, oldsal)
VALUES (:new.salary, :old.salary)
WHERE (salaryAudit.empid = old.empid);
UPDATE payroll
SET (salary)
VALUES (:new.salary)
WHERE (payroll.empid = old.empid);
END;
The concept is the same that #BobJarvis proposed but a lot simpler. Thanks
I have to create a trigger on an Employee table. If an INSERT or UPDATE statement is issued for the Employee table the trigger launches and makes sure that the value of 'salary' field meets the criteria in the job_min_sal table. After trying over and over I got a mutating table error and now am very frustrated and don't know what to do.
JOB_MIN_SALARY TABLE:
JOB VARCHAR2(50) PRIMARY KEY
MIN_SAL NUMBER(7,2) NOT NULL
The JOB_MIN_SAL table is populated with a variety of job titles and salaries. I am confused working with my trigger and wondering if I could get some assistance where to go from here
CREATE OR REPLACE TRIGGER employee_job_salary
BEFORE INSERT OR UPDATE OF SALARY on employee
FOR EACH ROW
DECLARE
v_salary NUMBER;
BEGIN
SELECT minimum_salary
INTO v_salary
FROM job_min_salary
WHERE UPPER(job) = UPPER(:NEW.job);
I know I am really far off I am just looking for help as for what this requires and what steps I need to take to get this. Thanks!
The EMPLOYEE table:
(
EMPLOYEE_ID NUMBER(4)
EMPLOYEE_NAME VARCHAR2(20)
JOB VARCHAR2(50)
MANAGER_ID NUMBER(4)
HIRE_DATE DATE
SALARY NUMBER(9)
COMMISION NUMBER(9)
DEPARTMENT_ID NUMBER(4)
);
i am supposing you are doing something like
comparing new salary with min salary criterion and update only if :new.SALARY >= v_salary
what are you doing if this is not met, are u trapping an exception or just ignoring the error or returning an error code to debug.
post more info
CREATE TABLE job_min_salary
(
job VARCHAR2(50) PRIMARY KEY,
min_sal NUMBER(7,2) NOT NULL
);
INSERT INTO job_min_salary VALUES('CEO','100');
-- 1 rows inserted.
CREATE TABLE employee
(
employee_id NUMBER(4),
employee_name VARCHAR2(20),
job VARCHAR2(50),
manager_id NUMBER(4),
hire_date DATE,
salary NUMBER(9),
commision NUMBER(9),
department_id NUMBER(4)
);
INSERT INTO employee VALUES(1, 'Name', 'CEO', 1, TO_DATE('2000-01-01', 'YYYY-MM-DD'), 80, 80, 1);
-- 1 rows inserted.
CREATE OR REPLACE TRIGGER employee_job_salary
BEFORE INSERT OR UPDATE OF salary ON employee
FOR EACH ROW
DECLARE
v_salary NUMBER(1);
BEGIN
SELECT 1
INTO v_salary
FROM job_min_salary
WHERE UPPER(job) = UPPER(:NEW.job)
AND :NEW.salary >= min_sal;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20999, 'Salary value is too low for given job');
END;
-- TRIGGER EMPLOYEE_JOB_SALARY compiled
SELECT * FROM employee;
-- 1 Name CEO 1 2000-01-01 00:00:00 80 80 1
UPDATE employee
SET salary = 10
WHERE job = 'CEO';
-- ORA-20999: Salary value is too low for given job
UPDATE employee
SET salary = 100
WHERE job = 'CEO';
-- 1 rows updated.
SELECT * FROM employee;
-- 1 Name CEO 1 2000-01-01 00:00:00 100 80 1