Reputation: 1
I'm trying to create a trigger that will update a column date by one month whenever a new row is added.
This is what I have, can someone tell me what I'm doing wrong?
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
IF :NEW.NextUpdate = SYSDATE
THEN
SET NextUpdate = ADD_MONTHS(SYSDATE,1);
END IF;
END;
Upvotes: 0
Views: 104
Reputation: 52000
This is what I have, can someone tell me what I'm doing wrong?
Assuming NextUpdate
having for default value SYSDATE
, as it has already been say, you IF
is maybe "not necessary"...
... but, as of myself, I think the real issue is SYSDATE
not guaranteeing to return the same value upon each call. If you don't believe me, try that http://sqlfiddle.com/#!4/1f810/2
So, your column might very well be properly initialized by SYSDATE
to, say "October, 26 2014 18:50:10+0000". But, in your trigger, SYSDATE
might very well return "October, 26 2014 18:50:11+0000". This would be bad luck, I admit. And maybe this is acceptable in your application. But in a more general case, this might easily become a hard to track bug.
Depending your needs, I would suggest one of those three options instead:
1) Assuming SYSDATE
is a "magical value" meaning "hey trigger! Compute the right value for NextUpdate
":
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
IF :NEW.NextUpdate <= SYSDATE
THEN
:NEW.NextUpdate := SYSDATE + INTERVAL '1' MONTH;
END IF;
END;
So, any time in the past will trigger the calculation of a new NextUpdate
. Including 1s in the past.
2) Override NextUpdate
from the trigger -- always:
CREATE TABLE Vehicle (value NUMBER(10),
NextUpdate DATE)
-- ^^^^^^^^^^^^^^^
-- No need for default here
-- as we override values
/
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
:NEW.NextUpdate := SYSDATE + INTERVAL '1' MONTH;
END;
/
INSERT INTO Vehicle(value) VALUES (1)
/
INSERT INTO Vehicle VALUES (2, TO_DATE('30/10/2014','DD/MM/YYYY'))
/
INSERT INTO Vehicle VALUES (3, TO_DATE('30/12/2014','DD/MM/YYYY'))
/
INSERT INTO Vehicle VALUES (4, NULL)
/
3) Set NextUpdate
defaults to SYSDATE + INTERVAL '1' MONTH, allow the user to change that when inserting. If you need it, a trigger might keep the LEAST
value (+/- the 1 second error as explained in preamble):
CREATE TABLE Vehicle (value NUMBER(10),
NextUpdate DATE DEFAULT SYSDATE + INTERVAL '1' MONTH)
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- set default to the "most probable" value
/
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
DECLARE
LimitNextUpdate DATE := SYSDATE + INTERVAL '1' MONTH;
BEGIN
:NEW.NextUpdate := LEAST(LimitNextUpdate,
NVL(:NEW.NextUpdate,LimitNextUpdate));
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- required if the used set the value to NULL
END;
/
INSERT INTO Vehicle(value) VALUES (1)
/
INSERT INTO Vehicle VALUES (2, TO_DATE('30/10/2014','DD/MM/YYYY'))
/
INSERT INTO Vehicle VALUES (3, TO_DATE('30/12/2014','DD/MM/YYYY'))
/
INSERT INTO Vehicle VALUES (4, NULL)
/
You will need to add extra logic (either in the trigger or as a check constraint) in order to reject NextUpdate
in the past.
Upvotes: 0
Reputation: 49082
There is no need of IF-END IF
block, whenever a new row is inserted, it will have sysdate. So, just update the NextUpdate
to ADD_MONTHS(SYSDATE,1)
directly. The check on IF :NEW.NextUpdate = SYSDATE
is not required.
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
:NEW.NextUpdate = ADD_MONTHS(SYSDATE,1);
END;
Upvotes: 1
Reputation: 5565
You can encounter a problem with your code when NextUpdate contains only date, without of hours, minutes and seconds. Try this:
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
IF :NEW.NextUpdate = trunc(SYSDATE)
THEN
SET NextUpdate = ADD_MONTHS(SYSDATE,1);
END IF;
END;
Or give us more details about what you want and what you get with your code.
Upvotes: 0