I have been given an assignment to create a trigger that works when tables are inserted or updated or deleted in a table. If it is a delete or update then the table must store the older values before the action on another table. If it is insert then the new row should be added to the new table. Also it should include the number of rows that are affected by each action. So far this is what I have done:
CREATE OR REPLACE TRIGGER archive_update
BEFORE INSERT OR UPDATE ON EMPLOYEE
FOR EACH ROW
BEGIN
INSERT INTO archive_emp(EMP_ID, FIRST_NAME, LAST_NAME, BIRTH_DAY,
SEX, SALARY, SUPER_ID, BRANCH_ID)
VALUES(:new.EMP_ID, :new.FIRST_NAME, :new.LAST_NAME,
:new.BIRTH_DAY, :new.SEX, :new.SALARY, :new.SUPER_ID, :new.BRANCH_ID);
END;
To check the dml operation you may use an IF condition with appropriate dml predicate
CREATE OR REPLACE TRIGGER archive_update
BEFORE
INSERT OR UPDATE ON EMPLOYEE
FOR EACH ROW
BEGIN
IF UPDATING OR DELETING THEN --You may add this
INSERT INTO archive_emp( emp_id, first_name, last_name,
birth_day, sex,salary,super_id,branch_id
) VALUES (:old.emp_id, :old.first_name,:old.last_name,:old.birth_day,
:old.sex,:old.salary,:old.super_id,:old.branch_id
);
ELSIF INSERTING THEN --and this
INSERT INTO archive_emp( emp_id, first_name, last_name,
birth_day, sex,salary,super_id,branch_id
) VALUES (:new.emp_id, :new.first_name,:new.last_name,:new.birth_day,
:new.sex,:new.salary,:new.super_id,:new.branch_id
);
END IF;
END;
/
Related
create trigger calculation after insert on employee
for each row
begin
if :new.updated_sal is null
then
update employee set updated_sal= (10/100)* salary
where id=:new.id;
end if;
end;
I would like to create a trigger on the employee table, whenever a new record is inserted in the same table, a 10% of salary in the salary column should be calculated and put into another column updated_sal.
If I try to insert a new record, it is showing that the table is mutated, etc
It's just the :new pseudorecord you need:
create trigger calculation
after insert on employee
for each row
begin
if :new.updated_sal is null then
:new.updated_sal := (10/100) * :new.salary;
end if;
end;
You need to use before insert trigger,
And use :New.updated_sal:= :new.salary * somevalue
To assign salary.
I have tables:
DEPARTMETS with dep_id(number), dep_name(varchar), manager_id(number) fields.
EMPLOYEES with employee_id(number), name(varchar), salary(number), manager_id(number)
I want to create a trigger which it is responsible for check if exists manager_id into table DEPARTMENTS when data is inserted or updated to table EMPLOYEES
Trigger could be something like:
create or update trigger manager_exists
before insert or update on employees
for each row
begin
if exists **new id** into Departments then
INSERT DATA IN EMPLOYEES
else
"Error: MANAGER_ID doesnt exists in Departments"
end if;
end manager_exists;
But I can't figure out how to create this trigger.
Note:I need it to be a trigger please. HELP!
This is how I understood the question:
create or replace trigger manager_exists
before insert or update on employees
for each row
declare
l_mgr number;
begin
select 1
into l_mgr
from dual
where exists (select null
from departments d
where d.manager_id = :new.manager_id
);
exception
when no_data_found then
raise_application_error(-20000, 'That manager does not exist in DEPARTMENTS');
end manager_exists;
In other words:
check whether MANAGER_ID you're trying to insert into EMPLOYEES table exists in DEPARTMENTS table
though, that doesn't make much sense to me; I'd say that you should check it vice versa - check whether MANAGER_ID you're trying to insert into DEPARTMENTS exists in EMPLOYEES table ... but that's not what you wrote (or I misunderstood what you said)
if so, fine, don't do anything (in a trigger); insert or update statement which caused the trigger to fire will do the job
if not, raise an error
Basically, i wanted to create a oracle trigger, which will track the Insert/Updates in a table and i wanted to insert these changed records alone into a new table on a daily basis.This new table data will be using for my daily data refresh (more like a CDC approach)
I was using below code. My expectation was when my CUSTOMER table got INSERT/UPDATED,that record should be available in CUSTOMER_D table.But i am missing something in below code
CREATE OR REPLACE TRIGGER CUST_TRIG AFTER INSERT OR UPDATE ON CUSTOMERS
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW WHEN (OLD.ID <> NEW.ID)
begin
IF INSERTING THEN
begin
INSERT INTO CUSTOMERS_D
(ID, NAME, AGE, ADDRESS, SALARY) values
(:new.ID, :new.NAME, :new.AGE, :new.ADDRESS, :new.SALARY);
-- assuming, there is an unique key on id
exception
when dup_val_on_index then
null;
end;
ELSIF UPDATING THEN
IF :NEW.ID = :OLD.ID THEN
UPDATE CUSTOMERS_D DWT
SET DWT.ID = :NEW.ID,
DWT.NAME = :NEW.NAME,
DWT.AGE = :NEW.AGE,
DWT.ADDRESS = :NEW.ADDRESS,
DWT.SALARY = :NEW.SALARY;
END IF;
MERGE INTO CUSTOMERS_D D
USING DUAL
ON (D.ID = :NEW.ID)
WHEN MATCHED THEN
UPDATE SET D.NAME = :NEW.NAME,
D.AGE = :NEW.AGE,
D.ADDRESS = :NEW.ADDRESS,
D.SALARY = :NEW.SALARY
WHEN NOT MATCHED THEN
INSERT
(D.ID, D.NAME, D.AGE, D.ADDRESS, D.SALARY) VALUES
(:NEW.ID, :NEW.NAME, :NEW.AGE, :NEW.ADDRESS, :NEW.SALARY);
END IF;
end test;
Your trigger in its present form has too many unnecessary constructs which you should get rid of. All you need ( as you confirmed in the comments ) is a single insert statement into customers_d whenever a record gets added or inserted from customers table.
I would recommend you to add another column indicating the time of transaction -MODIFIED_TIME
CREATE OR REPLACE TRIGGER CUST_TRIG
AFTER INSERT OR UPDATE ON CUSTOMERS
FOR EACH ROW
begin
INSERT INTO CUSTOMERS_D
(ID, NAME, AGE, ADDRESS, SALARY,modified_time )
values (:new.ID,
:new.NAME,
:new.AGE,
:new.ADDRESS,
:new.SALARY,
systimestamp);
end ;
/
DEMO
At first glance I can see the one issue in this trigger when new record is inserted the OLD.ID will be NULL so WHEN ((OLD.ID <> NEW.ID) will be FALSE and the trigger wont be invoked on INSERT into CUST_TRIG. Just add following condition:
FOR EACH ROW WHEN ((OLD.ID <> NEW.ID) OR (OLD.ID IS NULL))
I want to create trigger registring in new table employees whom salary is being raised above 5000 and didn't get salary higher than 5000 so far.
Trigger I wrote is returning error Error(2,41): PL/SQL: ORA-00984: column not allowed here.
Here's my trigger:
CREATE OR REPLACE TRIGGER emp_gotrich_trig BEFORE UPDATE OF salary ON employees
FOR EACH ROW BEGIN
IF :NEW.salary>5000 AND :OLD.salary<=5000 THEN
INSERT INTO emp_gotrich VALUES (employee_id, SYSDATE, :OLD.salary, :NEW.salary);
END IF;
END;
And here's emp_gotrich table:
CREATE TABLE emp_gotrich ( emp_id NUMBER(6), raise_date DATE, old_sal NUMBER(8,2), new_sal NUMBER(8,2) );
I guess that INSERT statemet isn't nested properly but i don't know what should i change.
I also tried to use 'WHEN' but i dont know where should i omitt colons, so it doeasn't work too.
CREATE OR REPLACE TRIGGER emp_getrich_log BEFORE UPDATE OF salary ON employees FOR EACH ROW
WHEN
NEW.salary>5000 AND OLD.salary<=5000;
BEGIN
INSERT INTO emp_gotrich VALUES(employee_id, SYSDATE, :OLD.salary, :NEW.salary);
END;
Please, help me find a way to run it.
You forgot to specify :OLD or :NEW on the employee_id value in your INSERT statement. I believe it should be:
INSERT INTO emp_gotrich
(EMP_ID, RAISE_DATE, OLD_SAL, NEW_SAL)
VALUES
(:OLD.employee_id, SYSDATE, :OLD.salary, :NEW.salary);
I suggest that a field list, such as the one I added, should always be included in an INSERT statement.
I have never created a trigger in Oracle before so I am looking for some direction.
I would like to create a trigger that increments an ID by one if the ID isnt in the insert statement.
The ID should start at 10000, and when a record is inserted the next ID should be 10001. If the insert statement contains a ID, it should override the auto increment.
ie
insert into t1 (firstname, lastname) values ('Michael','Jordan'),('Larry','Bird')
should look like:
firstname lastname id
Micahel Jordan 10000
Larry Bird 10001
insert into t1 (firstname, lastname, id) values ('Scottie','Pippen',50000)
should look like:
firstname lastname id
Micahel Jordan 10000
Larry Bird 10001
Scottie Pippen 50000
Something like this will work on 11g
CREATE SEQUENCE t1_id_seq
start with 10000
increment by 1;
CREATE TRIGGER trigger_name
BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
BEGIN
IF( :new.id IS NULL )
THEN
:new.id := t1_id_seq.nextval;
END IF;
END;
If you're on an earlier version, you'll need to do a SELECT INTO to get the next value from the sequence
CREATE TRIGGER trigger_name
BEFORE INSERT ON t1
FOR EACH ROW
DECLARE
BEGIN
IF( :new.id IS NULL )
THEN
SELECT t1_id_seq.nextval
INTO :new.id
FROM dual;
END IF;
END;
Be aware that Oracle sequences are not gap-free. So it is entirely possible that particular values will be skipped for a variety of reasons. Your first insert may have an ID of 10000 and the second may have an ID of 10020 if it's done minutes, hours, or days later.
Additionally, be aware that Oracle does not support specifying multiple rows in the VALUES clause as MySQL does. So rather than
insert into t1 (firstname, lastname) values ('Michael','Jordan'),('Larry','Bird')
you'd need two separate INSERT statements
insert into t1 (firstname, lastname) values ('Michael','Jordan');
insert into t1 (firstname, lastname) values ('Larry','Bird');
I would recommend to code this trigger with a condition on the trigger itself, not in the sql block.
CREATE OR REPLACE TRIGGER your_trigger
BEFORE INSERT ON your_table
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
WHEN (new.id IS NULL)
BEGIN
SELECT your_sequence.nextval
INTO :new.id
FROM dual;
END;
/
With this solution the trigger is only executed if the condition matches (id is null).
Otherwise the trigger is always executed and the block checks if id is null. The DB must execute the SQL block which does nothing on not null values.