PL/SQL ORACLE triggers - oracle

I'm trying to create a trigger that when you insert an employee in the company, assign a commission of 0.10 if it is from department 80. This is what I've tried so far:
CREATE OR REPLACE TRIGGER emp_com
BEFORE INSERT ON employees
FOR EACH ROW
WHEN (NEW.DEPARTMENT_ID= '80')
BEGIN
IF INSERTING THEN
:NEW.commission_pct := 0.10;
END IF;
END;

Your trigger should work fine in its current state; however, the "IF INSERTING" bit is redundant since your trigger only fires for inserts anyway.
CREATE OR REPLACE TRIGGER emp_com
BEFORE INSERT ON employees
FOR EACH ROW
WHEN (NEW.DEPARTMENT_ID= '80')
BEGIN
:NEW.commission_pct := 0.10;
END;

Related

How to fix: In a database of a monopoly game, if turn_number=0 (start turn), set bank account amount=3000;

trigger that in a database of a monopoly game, if turn_number=0 (start turn), set bank account amount=3000;
Create or replace trigger initial_turn
after insert on Recap_turn
for each row
when (new.turn_number=0)
declare
i integer;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
i:=3000;
update Recap_turn
set bank_account_amount=i
where (id_turn=:new.id_turn); commit;
end;
after the insert the bank_account_amount remain the same,instead of change to 3000
if you want to use trigger:
CREATE OR REPLACE TRIGGER initial_turn
BEFORE INSERT ON Recap_turn
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
begin
if inserting and :new.turn_number = 0 then
:new.bank_account_amount := 3000;
end if;
end;

PL/SQL Triggers

I am using these tables:
flights (flno, origin, destination, distance, departs, arrives, price)
aircraft (aid, aname, crusingrange)
employees (eid, ename, salary)
certified (eid,aid)
and I need to create a trigger that displays a warning when inserting an employee with "666" anywhere in his/her name.
This is what I came up with so far; I am lost with the rest of it.
set serveroutput on
create or replace trigger emp_warning
before insert
on employees
for each row
declare
v_name;
begin
select e.ename into v_ename
from employees e
A trigger cannot "display a warning"; a trigger can raise an exception.
In the context of the body of a before insert for each row trigger, the value being supplied for the column is available from :NEW.columname
For example:
BEGIN
IF :NEW.ename LIKE '%666%' THEN
RAISE_APPLICATION_ERROR(-20000, 'ename contains ''666''.');
END IF;
END;
It's not mandatory that you use the RAISE_APPLICATION_ERROR. You could emit some line(s) using DBMS_OUTPUT.PUT_LINE... the line could include whatever text you wanted, including the word "warning". But this isn't really a display of a warning.
Use a check constraint instead of a trigger:
alter table empoloyees modify ename check (ename not like '%666%');
I finally figured it out thanks for you help. This my answer to the trigger question.
set serveroutput on
create or replace trigger name_warning
before insert on employees
for each row
begin
if :new.ename like '%666%' then
dbms_output.put_line('Warning employees name contains 666');
end if;
end;
/

How can i fix this Mutating table from a procedure an trigger

This trigger will pass on inserted values to a procedure which will insert those values in another table. I'm getting a mutating table error. How can i fix this?
CREATE OR REPLACE TRIGGER ADD_INVOICE
BEFORE INSERT OR UPDATE OF APP_NO,C_NO ON APPOINTMENT
FOR EACH ROW
DECLARE
BEGIN
POP_INVOICE(:NEW.APP_NO,:NEW.C_NO,:NEW.APP_DATE);
END;
/
CREATE OR REPLACE PROCEDURE POP_INVOICE(
I_APP_NO IN INVOICE.APP_NO%TYPE,
I_C_NO IN INVOICE.C_NO%TYPE,
I_INV_DATE IN INVOICE.INV_DATE%TYPE)
AS
CURSOR C_POP IS SELECT PRICE FROM TREATMENT T,APPOINTMENT A
WHERE T.TRT_NO=A.TRT_NO
AND A.APP_NO=I_APP_NO;
V_BILL INVOICE.BILL%TYPE;
BEGIN
OPEN C_POP;
FETCH C_POP INTO V_BILL;
UPDATE INVOICE
SET INV_NO=INV_IDSEQ.NEXTVAL,
APP_NO=I_APP_NO,
C_NO=I_C_NO,
BILL=V_BILL,
INV_DATE=I_INV_DATE;
END;
/
The problem is caused by referencing the table with the trigger on it within the trigger itself. Changing the procedure to accept the TRT_NO as a parameter removes the need to include APPOINTMENT in the query, and so will avoid the mutating table exception. Depending on how many records there are for each treatment, you could even incorporate the cursor into your UPDATE statement.
I think this should do it, although I haven't been able to check against a database.
CREATE OR REPLACE TRIGGER ADD_INVOICE
BEFORE INSERT OR UPDATE OF APP_NO,C_NO ON APPOINTMENT
FOR EACH ROW
DECLARE
BEGIN
POP_INVOICE(:NEW.APP_NO,:NEW.C_NO,:NEW.APP_DATE,:NEW.TRT_NO);
END;
/
The revised procedure:
CREATE OR REPLACE PROCEDURE POP_INVOICE(
I_APP_NO IN INVOICE.APP_NO%TYPE,
I_C_NO IN INVOICE.C_NO%TYPE,
I_INV_DATE IN INVOICE.INV_DATE%TYPE,
I_TRT_NO IN APPOINTMENT.TRT_NO%TYPE
)
AS
CURSOR C_POP IS SELECT PRICE
FROM TREATMENT T
WHERE T.TRT_NO = I_TRT_NO;
V_BILL INVOICE.BILL%TYPE;
BEGIN
OPEN C_POP;
FETCH C_POP INTO V_BILL;
CLOSE C_POP;
INSERT INVOICE
(inv_no, app_no, c_no, bill, inv_date)
VALUES
(INV_IDSEQ.NEXTVAL, I_APP_NO, I_C_NO, V_BILL, I_INV_DATE);
END;
/

Inserting multiple records from a trigger in oracle

i created a trigger to insert the employeeIDs whenever a position is updated.
In some cases, there are many employees attached to one position so the trigger isnt able to insert all the employees (only 1). i need all the employee Ids
can any1 help me with this code?
Regards
create or replace trigger postn_updt
after update on postn
for each row
declare
cursor m is
select u.login
from user u,
party_per s
where u.row_id=s.person_id
and s.party_id=:new.row_id;
rownum varchar2(10);
begin
if updating ('postn_type_cd') then
open mult;
fetch mult into rownum;
insert into test123
(employee_number,type,request_date,remarks)
values
(( rownum,
'Updated',sysdate,''
);
close m;
end if;
end;
Triggers != Application code
If you embed application code in trigger like this then it will be horrible to maintain and debug and you'll always be encountering situations where a trigger-based approach won't work because of a mutating table error.
You would do much better to keep triggers for only auditing and other non-application activities, and put this kind of logic in the application itself.
to insert multiple rows you will need either a LOOP or some form of "INSERT... SELECT" statement.
eg.
create or replace trigger postn_updt
after update on postn
for each row
declare
cursor m is
select u.login
from user u,
party_per s
where u.row_id=s.person_id
and s.party_id=:new.row_id;
begin
if updating ('postn_type_cd') then
for mult_rec in m LOOP
insert into test123
(employee_number,type,request_date,remarks)
values
(( mult_rec.login,
'Updated',sysdate,''
);
END LOOP;
end if;
end;
OR
create or replace trigger postn_updt
after update on postn
for each row
declare
begin
if updating ('postn_type_cd') then
insert into test123
(employee_number,type,request_date,remarks)
select u.login ,'Updated',sysdate,''
from user u,
party_per s
where u.row_id=s.person_id
and s.party_id=:new.row_id;
end if;
end;

How to get number of rows affected by a statement when inside that statement's trigger

I have a statement level trigger that fires whenever INSERT UPDATE or DELETE operations are performed on a table (called customers). I want to display a message (to DBMS_OUTPUT) containing the number of rows that were inserted/updated/deleted.
I just want one message for each triggering statement, eg
'4 rows were inserted into customers table'.
How can I access the number of rows that are affected by the triggering statement from INSIDE the trigger declaration, ie XXX in the code below:
CREATE OR REPLACE TRIGGER customer_changes_trigger_2
AFTER INSERT OR UPDATE OR DELETE ON customers
DECLARE
v_operation VARCHAR(10);
v_number_rows NUMBER;
BEGIN
v_number := XXX;
IF INSERTING THEN
v_operation := 'inserted';
END IF;
IF UPDATING THEN
v_operation := 'updated';
END IF;
IF DELETING THEN
v_operation := 'deleted';
END IF;
DBMS_OUTPUT.PUT_LINE
(v_number_rows|| ' rows were ' || v_operation || ' from customers.');
END;
Can't find anything in the documentation, any help appreciated!
One way is to use a global variable to track the number of rows as there is no other way to get the row count from a statement level trigger. You would then need three triggers... one statement level to initialise the variable before the statement is run, one row level to add one to the variable for each row, one statement level to use the row count however you wish. First, set up the variable and a few procedures to help it:
create or replace package PKG_ROWCOUNT is
NUMROWS number;
procedure INIT_ROWCOUNT;
procedure ADD_ONE;
function GET_ROWCOUNT
return number;
end PKG_ROWCOUNT;
/
create or replace package body PKG_ROWCOUNT as
procedure INIT_ROWCOUNT is
begin
NUMROWS := 0;
end;
procedure ADD_ONE is
begin
NUMROWS := Nvl(NUMROWS, 0) + 1;
end;
function GET_ROWCOUNT
return number is
begin
return NUMROWS;
end;
end PKG_ROWCOUNT;
/
The first trigger to initialise the variable:
create or replace trigger CUSTOMER_CHANGES_TRIGGER_1
before insert or update or delete
on CUSTOMERS
begin
PKG_ROWCOUNT.INIT_ROWCOUNT;
end;
The second to update per row:
create or replace trigger CUSTOMER_CHANGES_TRIGGER_2
after insert or update or delete
on CUSTOMERS
for each row
begin
PKG_ROWCOUNT.ADD_ONE;
end;
/
The third to display the total:
create or replace trigger CUSTOMER_CHANGES_TRIGGER_3
after insert or update or delete
on CUSTOMERS
begin
Dbms_output.
PUT_LINE(PKG_ROWCOUNT.GET_ROWCOUNT || ' rows were affected.');
end;
I'm not 100$ sure if it's available inside AFTER trigger body, but you can try examining sql%rowcount

Resources