After insert auto increment trigger - sql

The problem here is that, we use an application called ArcGIS that creates an upper management layer for our database, and when our users use ArcGIS to create a new object in the database, it adds a default value (0) to the primary key, so when the second object is created it triggers an ORA error for having duplicate values.
So my idea was to create an auto increment trigger for our PK but use AFTER INSERT instead.
I couldn't find any example online for this specific case and simply switching BEFORE to AFTER gives an error saying that you can't use NEW with AFTER
SQL code of what I tried (taken from other questions):
CREATE OR REPLACE TRIGGER "IMOVEL_TRIGGER"
after insert on IMOVEL
for each row
begin
select IMOVEL_SEQ.nextval into :NEW.GEOCODIGO_IMOVEL from dual;
end;
It cant be a BEFORE INSERT trigger, because the application overwrites it
Simplifying, what I need is a AFTER INSERT trigger, that updates the PK to the sequence .nextval, it doesn't let me use :OLD or :NEW, so I'm not sure what must be done.
Or an update trigger that only runs after it is created
This is pretty new territory for me, having to learn SQL now just to solve this issue

You can change :NEW values only in a BEFORE trigger. By the time you reach the AFTER trigger, the row has already been inserted, so it's too late to change the columns.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_7004.htm says:
Restrictions on BEFORE Triggers
BEFORE triggers are subject to the following restrictions:
You cannot specify a BEFORE trigger on a view or an object view.
You can write to the :NEW value but not to the :OLD value.
Restrictions on AFTER Triggers
AFTER triggers are subject to the following restrictions:
You cannot specify an AFTER trigger on a view or an object view.
You cannot write either the :OLD or the :NEW value.
It's not clear why you want to use an AFTER trigger for assigning sequence values to the PK. The common solution is to use a BEFORE trigger.
See example in: How to create id with AUTO_INCREMENT on Oracle?

CREATE SEQUENCE IMOVEL_TRIGGER_SEQ START WITH 1;
Trigger definition:
CREATE OR REPLACE TRIGGER IMOVEL_TRIGGER
BEFORE INSERT ON IMOVEL
FOR EACH ROW
BEGIN
SELECT IMOVEL_TRIGGER_SEQ.NEXTVAL
INTO :new.GEOCODIGO_IMOVEL
FROM dual;
END;

Related

SQL integrity checks different on update and on insert

I have a SQL CHECK CONSTRAINT which checks values base on a column value (located on a different TABLE -> so FK is not an option).
Basically something like:
--Function
CREATE FUNCTION [dbo].[func_CHECK_ID_EXISTS]
(
if ...
return 1
else return 0
)
--CHECK CONSTRAINT
ALTER TABLE [dbo].[MY_TABLE]
ADD CONSTRAINT CHECK_ID_EXISTS
CHECK ([dbo].[func_CHECK_ID_EXISTS](MyColumn)=1);
This works perfectly.
Now I need this to evolve.
On an update, I would need to make the same integrity check than before (based on MyTable2.A).
But on an insert, I need to make an integrity check based on another column (based on MyTable2.B).
As far as I know, neither the SQL function func_CHECK_ID_EXISTS neither the constraint CHECK_ID_Eenter code hereXISTS knows if the element is being inserted or updated right?
So the check constraint does not seem to be an option anymore...
I had in mind to make an alternate solution with an update trigger and an insert trigger. Indeed I can set different conditions into each trigger.
But although the insert trigger can check the inserted element via the INSERTED pseudo table, I think I do not have this possibility for the UPDATE trigger.
I mean there is no UPDATED pseudo table is this correct?
So is there a possibility to compare the columns of the updated element within the update trigger?

Oracle Triggers, reliant on a key generated by a second trigger

I have question about triggers. For my database assignment, I have to create a trigger that automatically generates an ID number, which I have done.
The problem is a second trigger needs to be made that also acts on the same data. Both are inserts. Since they have to be separate, I am not sure how to make this work.
From what I have been taught the way to make a trigger act on the most recent addition is to use:
WHERE ID=:NEW.ID;
where ID is the primary key, but this does not work for me when the ID is being generated by a trigger. Is there a method of creating a trigger that acts on the most recent row added to the table that does not reference the primary key?
It is not clear why you need two triggers but let's assume it really makes sense (which I doubt).
Does the first trigger generates the ID from a sequence? In this case you can use value CURRVAL of the sequence. This pseudocolumn returns the current value of a sequence without increasing the value, see Sequence Pseudocolumns
If this does not fit your needs you can write a procedure which is then called be the trigger.
Would be like this:
create procedure PROC(aRow in ROWID) as
begin
...
end;
create first_trigger ....
begin
... whatever is needed at first trigger.
PROC(NEW.ROWID);
end;
create second_trigger ....
begin
... whatever is needed at second trigger.
PROC(NEW.ROWID);
end;
Both triggers would operate on the same row. You can also write current row values into a PL/SQL variable and process them by a Statement-Trigger (i.e. no row-level-trigger)

Get a reference to insert rows with triggers

I'm trying to get a reference to a set of rows that I'm trying to insert into a table through a multiple insert. For example if I execute:
INSERT INTO T VALUES (0,'A'),(1,'B'),(2,'C')
I would like to get a reference in a before insert trigger to a "table" that contains these 3 rows. Is that possible?
And another question: what does a REFERENCING NEW_TABLE represents in a before trigger (maybe could this be the answer to the first question)?
Thanks
According to documentation:
REFERENCING NEW TABLE AS identifier
Specifies a temporary table name which identifies the affected rows as modified by the triggering SQL operation and by any SET
statement in a BEFORE trigger that has already executed.
Also take a look:
FOR EACH STATEMENT
Specifies that the triggered action is to be applied only once for the whole statement. This type of trigger granularity cannot be
specified for a BEFORE trigger or an INSTEAD OF trigger (SQLSTATE
42613). If specified, an UPDATE or DELETE trigger is activated, even
if no rows are affected by the triggering UPDATE or DELETE statement.
maybe it will suite better your needs (of course you need to go with AFTER trigger)

mutating table with this trigger oracle database

Use Oracle database and need to store all rows in lower case. All INSERTand UPDATE should insert and update rows with lower case data. I wrote a trigger to do it. Read a lot of about table mutation with triggers.Very confused, will this code raise mutate error or not. Please, write here, if it will.
create or replace trigger employee_name
before update or insert on employee
for each row
begin
/* convert character values to lower case */
:new.lastname := lower( :new.lastname );
:new.firstname :=lower( :new.firstname );
end;
/
The trigger will not raise a mutating table error as you're not selecting from the table your trigger is on; you're only reassigning values, which is what triggers are designed to do.
It's worth noting that this can also be accomplished with a CHECK constraint, which will force everyone updating or inserting into the table to lower case everything:
alter table employee_name
add constraint chk_emp_name_lastname
check ( lastname = lower(lastname) )
Whilst this will increase update/insert times (not necessarily more than using a trigger) it doesn't silently change data being entered but instead complains that the data is incorrect. This is sometimes a better approach.
this code not raise exception
because you not try select from table which trigger executing
This should not raise any errors. Mutate errors occur when you read (or modify) some other rows from BEFORE trigger.
NOTE: there are situations where BEFORE trigger is fired more that once for the SAME row.
In order to guarantee consistency Oracle would have to justify, that your trigger body is "idempotent": e.i. each execution on the same input gives the same result.

How to put SELECT inside trigger in IBM DB2

I want my database to show the table every time while I insert a new row. My code is able to compile but It don't show the table after I insert a new row.
Below is my code :
create trigger show_all
after insert ON Toy
for each row mode db2sql
select * from Toy
This isn't possible.
Triggers don't return a value to the statement (insert) that caused the trigger to fire. Further, that behaviour wouldn't even be possible because multiple triggers could fire in response to an insert, which would get to return something?
You could create a stored procedure that performs an insert and then returns the result of a select, and then call that function instead of inserting directly.