I have a trigger somewhat like this (Sorry can't display actual sql because of company rules and this is from a different machine):
create or replace trigger TR_TABLE_X_AU
after update
on TABLE_X
for each row
declare
cursor cursor_select_fk is
select FK_FOR_ANOTHER_TABLE
from TABLE_Y Y, TABLE_Z Z
where :NEW.JOINING_COL = Y.JOINING_COL
and Y.JOINING_COL = Z.JOINING_COL
and :NEW.FILTER_CONDITION_1 = Y.FILTER_CONDITION_1
and :NEW.FILTER_CONDITION_2 = Y.FILTER_CONDITION_2
and :NEW.SOME_DATE_COL = (select max(SOME_DATE_COL)
from TABLE_X
where FILTER_CONDITION_1 = :NEW.FILTER_CONDITION_1
and FILTER_CONDITION_2 = :NEW.FILTER_CONDITION_2)
begin
for rec in cursor_select_fk loop
PCK_SOME_PACKAGE.SOME_PROC(rec.FK_FOR_ANOTHER_TABLE);
end loop;
end TR_TABLE_X_AU;
We resulted to triggers since it is an enhancement. The nested query selecting the max date seems to be the cause of the problem. Changing it to sysdate results to no exceptions. Any idea on how I can get the max date during the execution of the trigger for TABLE_X? Thanks!
Also, it seems similar functions such as count,sum,etc... produces the same error. Anyone knows a workaround to this?
A row trigger cannot read from the table it is firing on if it is known that the triggering statement might affect more than one row (and an update can affect more than one row in general).
This error message is in place to save your butt from the fires of "data integrity does not exist in my database anymore". Meaning it is happening to save you from a grievous error in logic.
.. We resulted to triggers since it is an enhancement. ...
i hate that reasoning. Software exists to be changed. Triggers are horrible for trying to automagically slide a change into production. So so so so so many side effects and long term downsides.
http://www.oracle.com/technetwork/issue-archive/2008/08-sep/o58asktom-101055.html Think about this - you do an update to the SOME_DATE_COL - and it affects more than one row. IF this trigger worked, IF this trigger could read table_x while the update was taking place - think about what would or could happen.
Every time a row is updated, you try to read the "max" value - only remember, we are updating the some_date_col - so you are reading the table in the middle of the update - while the data is being updated (HYPOTHETICALLY, we don't allow such a bad thing to happen). You'll read a max value that was NEVER a max value at any point in time potentially. You'll read and process data that should never have been seen.
For example, suppose the data in the table was:
...... 01-JAN-2012 ......
....... 02-JAN-2012 ........
and the update just happened to hit it in that order. the update you fired was:
update table_x set some_date_col = some_date_col + 5 .......;
so that will change 01-jan to 06-jan, AND THEN 02-jan into 07-jan.
The only max dates EVER in this table were 02-jan (before the update) and 07-jan
(after the update). However, what would your trigger hypothetically see??? It would see 01-jan get turned into 06-jan and it would read that out and process it as if that was the max date at some point. BUT IT NEVER WAS. Never.
and then it would process 07-jan as the max date for the second row.
But, it would only do that if the update hit those rows in that specific order. What if the rows were processed:
....... 02-JAN-2012 ........
...... 01-JAN-2012 ......
instead? Now - given the same exact set of data, the SAME data, just processed in a different order because of the way the rows existed on disk - we get an entirely different answer!!!! ouch.
so, we do not permit this. We do not allow you to program such inconsistencies into your application.
I strongly (as strongly as I can) encourage you to abandon the trigger and implement the code logic you need as a straightforward code change. Software exists
to be modified, that is why we call it software and not hardware.
Your trigger has another potential logic bomb. What if two or more sessions are modifying table_x at the same time? Think about the race conditions that exist now. Might you need to LOCK some data to prevent someone from creating a max(some_date_col) you cannot see? I cannot tell from the code snippet if this is relevant, but it likely could be.
I hesitate to post this next link, you could find it easily enough by searching. It shows how to postpone your processing of the modified data until an AFTER trigger - when the table is 'stable'...
http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551198119097816936