Compare Date with Trigger on Oracle SQL - sql

I have a table with those columns:
DateDebVal DATE
DateFinVal DATE
isCurrent NUMBER
And I need to have a trigger that do something like this:
CREATE TRIGGER check_date
AFTER INSERT OR UPDATE ON tablename
FOR EACH ROW
BEGIN
IF sysdate < DateFinVal
set isCurrent = 1
ELSE
set isCurrent = 0
END;
Can I compare those dates? Is it a good idea to use a trigger instead of a view or a procedure?

Dates can absolutely be compared, but assignment is done using := in PL/SQL (not with set)
If you want to change the value of a newly inserted row, you have to use a BEFORE trigger:
CREATE TRIGGER check_date
BEFORE INSERT OR UPDATE ON tablename
FOR EACH ROW
BEGIN
IF sysdate < :new.datefinval
:new.iscurrent := 1;
ELSE
:new.iscurrent := 0;
END IF;
END;
/
Online example: https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=796347f1b5811448dddf2d0a532c2c2c

Sysdate and DateFinVal are of DATE type so you would compare those. It depends what for you need this trigger.

Related

how to convert a mutating trigger to a stored procedure

I have the following trigger:
CREATE OR REPLACE TRIGGER planning_trig BEFORE
UPDATE OF planned_remediation_date ON evergreen
FOR EACH ROW
DECLARE
planned_remediation_date DATE;
BEGIN
SELECT
planned_remediation_date
INTO planned_remediation_date
FROM
evergreen
WHERE
hostname = :new.hostname
AND instance_name = :new.instance_name
AND product_home = :new.product_home
AND it_service = :new.it_service
AND sw_name = :new.sw_name;
IF
planned_remediation_date IS NOT NULL
AND planned_remediation_date > trunc(sysdate)
THEN
UPDATE evergreen
SET
planning_status = 'planned';
ELSE
UPDATE evergreen
SET
planning_status = 'overdue';
END IF;
END;
/
After an update of the row in my table evergreen I get this error:
ORA-04091: table PTR.EVERGREEN is mutating, trigger/function may not see it
I believe the error comes from the fact that I'm trying to update the very same table the trigger is firing on. I read that the best way to handle updates in the same table are stored procedures but I'm quite new to oracle and don't know how to achieve that. Another possibility I heard is AUTONOMOUS_TRANSACTION Pragma but not sure either if this applies to my case.
A little more background, the underlying table has a composite unique key (hostname,instance_name,product_home,it_service,sw_name) and I want to update an existing column on this table called planning_status based on the updated value of planned_remediation_date. If that value is not null and greater then today then update with planned else overdue.
Expression planned_remediation_date IS NOT NULL is redundant. planned_remediation_date > trunc(sysdate) is never TRUE when planned_remediation_date is NULL.
Your trigger can be written much shorter:
CREATE OR REPLACE TRIGGER planning_trig
BEFORE UPDATE OF planned_remediation_date ON evergreen
FOR EACH ROW
BEGIN
IF :new.planned_remediation_date > trunc(sysdate) THEN
:new.planning_status := 'planned';
ELSE
:new.planning_status := 'overdue';
END IF;
END;
/
I guess you like to modify the updated row, not other rows in that table. Otherwise you would need a procedure or a COMPOUND trigger

Error while working with dates in pl/sql?

This is how it's supposed to work:
I have a table called Pro2 with a column called finall that is a date and another one called validade. If finall has already happened or is happening validade is set to 0.
BEGIN
FOR validade in (SELECT * FROM PRO2 WHERE TRUNC(finall)<= TRNCU(SYSDATE))
LOOP
SET validade = 0
END LOOP;
END;
I'm new in PL/SQL please help!
You have an error in your second TRUNC command.
You aren't supposed to set validade (which is a CURSOR) to any value.
Assignment operator is := and not SET in PL/SQL.
Try this:
BEGIN
FOR r_record IN (SELECT *
FROM PRO2
WHERE TRUNC(finall) <= TRUNC(SYSDATE))
LOOP
UPDATE PRO2 t1
SET t1.validade = 0
WHERE t1.id = r_record.id;
END LOOP;
END;
You shouldn't use PL/SQL for such thing!
Use SQL when it is possible!
UPDATE PRO2
SET validade = 0
WHERE TRUNC(finall) <= TRUNC(SYSDATE);
Every well-designed Oracle table has a primary key, often called id or ending with it. That is what Alex meant by t1.id. You should ask for the column(-combination) that makes the primary key for PRO2 and substitute that.
DML code like the shown UPDATE can be included in PLSQL and is really the best solution:
BEGIN
-- other things here ....
UPDATE pro2
SET validade = 0
WHERE TRUNC( finall ) <= TRUNC( SYSDATE );
-- and here ...
END;

Wondering why my SQL statement is ignoring my SET symbol

This is my SQL trigger and it is suppose to change the reorder value to Y or N depending if ON_HAND is less than or greater than the MINIMUM. The problem is it's ignoring the set statement completely. Do I have to arrange these differently?
CREATE OR REPLACE TRIGGER TRG_REORDER
AFTER UPDATE OF ON_HAND, MINIMUM ON PART
BEGIN
IF ON_HAND <= MINIMUM THEN
SET REORDER = 'Y';
ELSE ON_HAND > MINIMUM
SET REORDER = 'N';
END IF;
END;
Trigger bodies use PL/SQL syntax, not SQL. So for assignment you need := not set.
Your code has some other syntax errors.
You need to refer to the :new values of the columns.
You don't need a condition in the ELSE clause.
In order to modify the values of columns in a trigger, it must be a BEFORE trigger and fire FOR EACH ROW.
So fixing all that, this should now work for you (caveat: untested code).
CREATE OR REPLACE TRIGGER TRG_REORDER
before UPDATE OF ON_HAND, MINIMUM ON PART
for each row
BEGIN
IF :new.ON_HAND <= :new.MINIMUM THEN
:new.REORDER = 'Y';
ELSE
:new.REORDER = 'N';
END IF;
END;
I don't know Oracle triggers but I suspect you want a BEFORE trigger and an assignment that looks something like this.
:new.REORDER := case when :new.ON_HAND <= :new.MINIMUM then 'Y' else 'N' end;
Check here to get started:
http://www.techonthenet.com/oracle/triggers/before_update.php

Automatically update a column in a table with a trigger

I'm having a problem with a trigger code (table mutation and more!) and I can't find
what is the problem.
Basically, I have a table SEMESTER(id_semester, semester_name, begin_date, end_date).
On the insertion of a row, I want the semester_name to be updated with a value according
to what's in begin_date. For example, if the begin_date is '2000-01-01', I want the value of
semester_name to be W00 (for winter 2000).
My first try was to write an 'after insert' trigger, which didn't work because of a table mutation error. Here it is:
CREATE TRIGGER Test
BEFORE INSERT ON Semester
FOR EACH ROW
DECLARE
sem CHAR(1);
year CHAR(2);
BEGIN
-- begin_date is either 1, 5 or 9.
IF (EXTRACT(MONTH FROM :new.begin_date) = '1') THEN
saison := 'W';
ELSIF (EXTRACT(MONTH FROM :new.begin_date) = '5') THEN
saison := 'S';
ELSE
saison := 'F';
END IF;
year := TO_CHAR(:new.date_debut, 'MM');
UPDATE Semester
SET semester_name = CONCAT(sem, year)
WHERE id_semester = :new.id_semester;
END;
/
After, I tried to make a 'before insert' trigger, thinking it would work better but it does not.
Anyone could point me in the right direction?
Thanks!
Assuming id_semester is the primary key, instead of an UPDATE statement, you would just want to assign the :new.semester_name
:new.semester_name := concat( sem, year );
The mutanting table error occurs only with "each row" kind of triggers, try to change your after insert trigger for a "statement" type

Oracle to_char subquery in Trigger

I have a table (Meeting) with date type attribute (MeetDate) and another varchar2 type attribute (WorkWeek). I'm trying to do an After trigger to fill in the WorkWeek field based on the MeetDate value using the to_char function. Tried the following codes separately and they compile without errors but when I try to insert a row with Null for WorkWeek, it gives me a 'mutating trigger/function may not see it' error. What am I doing wrong here? thanks in advance to any help.
--Code 1
Create or Replace Trigger Update_WorkWeek
After Insert On Meeting
For Each Row
Begin
Update Meeting
Set WorkWeek = (Select to_char(:new.MeetDate, 'YYYY IW') From Dual)
Where MeetID = :new.MeetID;
End;
/
show Errors;
--Code 2
Create or Replace Trigger Update_WorkWeek
After Insert On Meeting
For Each Row
Begin
if :New.WorkWeek is Null then
Update Meeting
Set WorkWeek = (Select to_char(:new.MeetDate, 'YYYY IW') From Dual)
Where MeetID = :new.MeetID;
End if;
End;
/
show Errors;
You just want a trigger to change the value of a column before it gets inserted - and it's on the same row, so you don't need an UPDATE:
Create or Replace Trigger Update_WorkWeek
BEFORE Insert On Meeting
For Each Row
Begin
:new.WorkWeek := to_char(:new.MeetDate, 'YYYY IW');
End;
/
show Errors;
You might want the column kept up-to-date if the MeetDate is changed, i.e.:
Create or Replace Trigger Update_WorkWeek
BEFORE Insert
OR Update OF MeetDate
On Meeting
For Each Row
Begin
:new.WorkWeek := to_char(:new.MeetDate, 'YYYY IW');
End;
/
show Errors;