I'm trying to create a trigger which would prevent insertions, updates and deletions if done outside office hours(i.e, other than 8-18 hours or sundays)
here is my code:
CREATE OR REPLACE TRIGGER HOLIDAY
BEFORE DELETE OR INSERT OR UPDATE ON DEPT FOR EACH ROW
BEGIN
IF ((EXTRACT(DAY FROM SYSDATE)='SUNDAY') OR (EXTRACT(HOUR FROM LOCALTIMESTAMP) NOT BETWEEN 8 AND 18)) THEN
RAISE_APPLICATION_ERROR(-20001,'ILLEGAL OPERATION - OUT OF OFFICE HOURS OR HOLIDAY!');
END IF ;
END;
/
the trigger was created.
Today is sunday and when i try to insert a row, the application error is not raise, instead, what i get is:
SQL> #/home/divya/A43.SQL
Trigger created.
SQL> DELETE FROM DEPT WHERE D_NO = 'D3' ;
DELETE FROM DEPT WHERE D_NO = 'D3'
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at "DIVYA12345.HOLIDAY", line 2
ORA-04088: error during execution of trigger 'DIVYA12345.HOLIDAY'
Can someeone please tell me exactly what is the error? show errors displays - no errors as output. Any help is highly appreciated. thanks in advance.
You get the error because EXTRACT(DAY FROM SYSDATE) returns the number of the day in month, not its name. To retrieve the name, you can use TO_CHAR(SYSDATE, 'DAY') instead, or to_char(sysdate,'fmDY', 'nls_date_language = ENGLISH') as suggested in the comments:
CREATE OR REPLACE TRIGGER HOLIDAY
BEFORE DELETE OR INSERT OR UPDATE ON DEPT FOR EACH ROW
BEGIN
IF (TO_CHAR(sysdate,'fmDY', 'nls_date_language = ENGLISH')='SUNDAY') OR (EXTRACT(HOUR FROM LOCALTIMESTAMP) NOT BETWEEN 8 AND 18)) THEN
RAISE_APPLICATION_ERROR(-20001,'ILLEGAL OPERATION - OUT OF OFFICE HOURS OR HOLIDAY!');
END IF ;
END;
/
Related
CREATE OR REPLACE TRIGGER trg_week_day
BEFORE
INSERT OR UPDATE OR DELETE
ON emp
BEGIN
IF (TO_CHAR(SYSDATE, 'DY') = 'SAT' OR TO_CHAR(SYSDATE, 'DY') = 'SUN')
THEN
raise_application_error(-20000,'User: ' ||user ||' May not change employee table during the weekend.');
else
dbms_output.put_line('Today is not Weekend, Let us Work');
END IF;
END;
/
UPDATE emp
SET sal = 32000
WHERE empno= 101;
I get the following error
Trigger created.
ORA-20000: User: APEX_PUBLIC_USER May not change employee table during the weekend.
ORA-06512: at "SQL_XDFWSAJBEIBDLNRPNGQWTGKQO.TRG_WEEK_DAY", line 5
ORA-06512: at "SYS.DBMS_SQL", line 1721
Edit 1: I need to create a trigger on emp table before insert update or delete command is done on emp table on weekend.
i understand the ORA-20000: error
but I don't understand how to remove the ORA-06512: and what is it about...
Understanding the below comments I get that it is because of unhandled exceptions...is there a way to resolve it? in this code
Thank everyone for the help.
Table:
create table department(deptno number, deptname varchar2(50), deptloc varchar2(50));
insert into department values(1,'A','X');
insert into department values(2,'B','Y');
insert into department values(3,'C','Z');
Stored procedure :
create or replace procedure secure_dml(i_month IN varchar2)
is
begin
if i_month <> 'March' then
dbms_output.put_line('You can modify or add a department only at the end of a financial year');
else
--should I write insert/update DML statement?
end;
Trigger :
create or replace trigger tr_check_dept before insert on department
begin
dbms_output.put_line('Record inserted');
end;
Requirement :
Implement the following business rule with the help of a Procedure and a Trigger :-
i. Changes to the data in the Department table, will be allowed only in the month of March.
ii. Create a procedure named SECURE_DML that prevents the DML statement from executing in any other month other than March. In case, if a user tries to modify the table in any other month apart from March, the procedure should display a message
“You can modify or add a department only at the end of a financial year”
iii. Create a statement level trigger named TR_CHECK_DEPT on the Department table that calls the above procedure.
iv. Test it by inserting a new record in the Department table
Basically, you could do everything within a trigger, but OK - that's some kind of a homework. Here's how I understood it.
Procedure doesn't do anything "smart", just displays the message. Note that DBMS_OUTPUT.PUT_LINE call displays a message, it doesn't prevent anyone to do anything - instead of it, you should raise_application_error.
The answer to your question
should I write insert/update DML statement?
is - in my opinion - NO, you shouldn't.
Trigger calls that procedure. Yours doesn't check the month, while it should (i.e. move that control from procedure to trigger).
Everything put together might look like this:
SQL> create or replace procedure secure_dml
2 is
3 begin
4 raise_application_error(-20000,
5 'You can modify or add a department only at the end of a financial year');
6 end;
7 /
Procedure created.
SQL> create or replace trigger tr_check_dept
2 before insert on department
3 for each row
4 begin
5 if extract(month from sysdate) <> 3 then
6 secure_dml;
7 end if;
8 end;
9 /
Trigger created.
SQL> insert into department(deptno, deptname, deptloc)
2 values (4, 'D', 'W');
insert into department(deptno, deptname, deptloc)
*
ERROR at line 1:
ORA-20000: You can modify or add a department only at the end of a financial year
ORA-06512: at "SCOTT.SECURE_DML", line 4
ORA-06512: at "SCOTT.TR_CHECK_DEPT", line 3
ORA-04088: error during execution of trigger 'SCOTT.TR_CHECK_DEPT'
SQL>
Just for testing purposes, as it is September today, let's modify trigger code so that it works for this month (instead of March) and see what INSERT does in that case.
SQL> create or replace trigger tr_check_dept
2 before insert on department
3 for each row
4 begin
5 if extract(month from sysdate) <> 9 then --> this line was changed
6 secure_dml;
7 end if;
8 end;
9 /
Trigger created.
SQL> insert into department(deptno, deptname, deptloc)
2 values (4, 'D', 'W');
1 row created.
SQL>
Right; now it works.
I have employee table in oracle.I want to create a trigger that will avoid insertion of data on sun day. please tell me the program?following program not working.
Here's an example trigger that checks for week day and, if day is sunday (7), throws an user defined exception ORA-20000:
CREATE OR REPLACE TRIGGER trg_sunday
BEFORE INSERT ON employee
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF TO_CHAR(SYSDATE, 'D') = '7' THEN
RAISE_APPLICATION_ERROR(-20000, 'Cannot insert record on sunday');
END IF;
END;
Please check which number identifies sunday, it depends on the local NLS settings of the database. Here in Italy (NLS_TERRITORY='ITALY') Sunday is identified by 7 but with different database NLS setting the number may vary.
You may take a look at Day of week (1-7) and NLS settings
The trigger remains the same but the query goes like below:
to check whats day today"
select to_char(to_date('08/08/2016','dd/mm/yyyy'), 'DY'),TO_CHAR(SYSDATE, 'D') from dual;
To check next sunday:
select to_char(to_date('14/08/2016','dd/mm/yyyy'), 'DY'),TO_CHAR(to_date('14/08/2016','dd/mm/yyyy'), 'D') from dual;
The correct code should be:
CREATE OR REPLACE TRIGGER trg_sunday
BEFORE INSERT ON employee
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF TO_CHAR(SYSDATE, 'D') = '1' THEN ---Should be 1 rather than 7
RAISE_APPLICATION_ERROR(-20000, 'Cannot insert record on sunday');
END IF;
END;
You can create your trigger as shown in below code snippet.
CREATE OR REPLACE TRIGGER sunday_prevent
BEFORE INSERT ON account
FOR EACH ROW
Begin
IF TO_CHAR(SYSDATE,'day')='sunday' then
raise_application_error(-20000,'Today is Sunday so you not perform any transaction');
END IF;
END;
/
Hope someone can help with this. I am new to triggers and I am trying to create a trigger that checks to see if the record being modified has a specific value.
example
I have a table called Filing that has a filing_id and a filing_status, I want to prevent someone from updating or deleting any records in that table has a filing_status="FILED".
so if i have the following
Filing_id Filing_status Val
--------- ------------- ---
0 Filed X
If someone tried to modify Val the trigger should stop it
I have created the following trigger:
CREATE or replace TRIGGER TRG_PREV_FILING
BEFORE DELETE or UPDATE
ON PF.FILING
FOR EACH ROW
declare
rowcnt number;
BEGIN
SELECT COUNT(filing_id) INTO rowcnt FROM PF.FILING
where status = 'FILED'
and filing_id = :new.filing_id;
if (rowcnt > 0)
then
raise_application_error (-20100, 'You can not delete Or Update initial record');
end if;
END;
The problem I am facing is I am getting:ORA-04091 which is "Table Filing is mutating, Trigger/function may not see it"
So basically I can't query on the same table that I am executing the trigger on? Is that the problem in my case and does anyone know a work around this?
I appreciate any help
You do not have to query the table trigger is firing on to be able to do that kind of check. You can get value of a column that is being modified using :old. Here is an example:
SQL> create table filing(
2 status varchar2(31),
3 val number
4 );
Table created
SQL> create or replace trigger TRG_FILING before delete or update on FILING
2 for each row
3 begin
4 if lower(:old.status) = 'filed'
5 then
6 raise_application_error(-20000, 'You cannot delete or modify this record');
7 end if;
8 end;
SQL> /
Trigger created
SQL> insert into FILING values('FILED', null);
1 row inserted
SQL> insert into filing values('OK', 1);
1 row inserted
SQL> commit;
Commit complete
SQL> select *
2 from filing;
STATUS VAL
------------------------------- ----------
FILED
OK 1
SQL> delete
2 from filing
3 where val is null;
ORA-20000: You cannot delete or modify this record
ORA-06512: at "HR.TRG_FILING", line 4
ORA-04088: error during execution of trigger 'HR.TRG_FILING'
The basic point is that you should design you database in a way that the trigger does its validation based on the updated/deleted row. If you have several rows with the same filing_id then you can overwork you database design. Maybe you really only check against the own table in which case you can use :old. But when you have several rows to check (which I assume because you make a count) then you have to use two tables. Here is a suggestion.
create table filing_status (filing_id number, status varchar2(10));
create table filing_content (filing_id number, content_id number, content varchar2(200));
CREATE or replace TRIGGER TRG_PREV_FILING
BEFORE DELETE or UPDATE
ON FILING_content
FOR EACH ROW
declare
rowcnt number;
BEGIN
SELECT COUNT(filing_id) INTO rowcnt FROM FILING_status
where status = 'FILED'
and filing_id = :new.filing_id;
if (rowcnt > 0)
then
raise_application_error (-20100, 'You can not delete Or update filed record');
end if;
END;
/
insert into filing_status values (1, 'FILING');
insert into filing_content values (1, 1, 'foo');
insert into filing_content values (1, 2, 'bar');
insert into filing_status values (1, 'FILED');
update filing_content set content = 'bahr' where filing_id = 1 and content_id = 2;
ERROR at line 1:
ORA-20100: You can not delete Or update filed record
ORA-06512: at "DEMO.TRG_PREV_FILING", line 9
ORA-04088: error during execution of trigger 'DEMO.TRG_PREV_FILING'
I'm very new for trigger, now this what i was trying. I've two tables INSERTED and ORDER_INFO, both have the same column name ORDER_ID, ORDER_DATE. I've scenario, where client will be placing his/her order then, order information will be stored into INSERTED table, then by using this trigger, it'll insert into another table ORDER_INFO after satisfying the condition, which has been written.
create trigger tri_check
AFTER INSERT ON inserted FOR EACH ROW
DECLARE
v_date DATE;
BEGIN
SELECT order_date INTO v_date FROM inserted;
if (v_date)< (sysdate + 2) then
raiserror('You cannot take an order to be delivered less than 2 days from now',16, 1);
else
INSERT INTO orders_info
( order_id,order_date)
VALUES
(:new.order_id,v_date);
end if;
end;
But, when i'm executing the above trigger, then i'm getting this error.
ERROR at line 8: PL/SQL: SQL Statement ignored
6. SELECT order_date INTO v_date FROM inserted;
7. if (v_date)< (sysdate + 2) then
8. raiserror('You cannot take an order to be delivered less than 2 days from now',16, 1);
9. else
10. INSERT INTO orders_info
EDIT
Now, i made the same structure table into SYSTEM user, and got the same error. Table or View does not exist
Need help !! Thanks in advance !!
The message seems to indicate a problem with the 'raiserror' procedure. I'm not familiar with such a procedure in standard PL/SQL - did you mean RAISE_APPLICATION_ERROR? However, and perhaps more to the point, when using a trigger there's no need to do a SELECT from the table. All the data being inserted is available to the trigger. I suggest changing your trigger to be something like the following:
create trigger tri_check
AFTER INSERT ON inserted
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
if :new.ORDER_DATE < sysdate + INTERVAL '2' DAY then
RAISE_APPLICATION_ERROR(-20000, 'You cannot take an order to be delivered less than 2 days from now');
else
INSERT INTO orders_info
(order_id, order_date)
VALUES
(:new.order_id, :new.ORDER_DATE);
end if;
end TRI_CHECK;
Share and enjoy.
You can just use the :NEW and :OLD values instead of your select:
CREATE TRIGGER tri_check
AFTER INSERT
ON inserted
FOR EACH ROW
DECLARE
BEGIN
IF :new.order_date < (SYSDATE + 2)
THEN
raiserror (
'You cannot take an order to be delivered less than 2 days from now',
16,
1);
ELSE
INSERT INTO orders_info (order_id, order_date)
VALUES (:new.order_id, :new.order_date);
END IF;
END;
What is your raiserror procedure? Do you have access permissions granted on it?
Hope it helps...
EDIT:
OK, from your error, and the error you posted on #Bob Jarvis' answer, you might not have INSERT privilege on the ORDERS_INFO table. You also should check your permissions on the INSERTED table too.
Check your permissions with your DBA.
If raiserror is not a defined procedure or you don't have access to it then use the RAISE_APPLICATION_ERROR method for raising an error as Bob suggests.