How to check in Trigger what has been given in the where clause? - sql

I am writing an INSTEAD OF UPDATE trigger and I want to identify what columns has been given to the WHERE clause of the UPDATE statement that triggers the trigger.
For example,
Let's say that we have the table below
table_name
--COL1
--COL2
--COL3
--COL4
I want, when an update is performed
e.g.UPDATE table_name SET COL1=VAL1,COL2=VAL2 WHERE COL3=VAL3
to be able to say in my trigger
CREATE or replace TRIGGER DEVICES_VIEW_TR
INSTEAD OF UPDATE ON DEVICES_VW
BEGIN
IF (COL3 has been given in the where clause) THEN
variable=getValueOf(COL3);
ELSEIF (COL4 has been given in the where clause) THEN
variable=getValueOf(COL4);
END IF;
END;
/
Can this be done?
Thanks

You can use the UPDATING('column name') in your trigger:
-- in INSTEAD OF trigger body:
IF updating('COL1') THEN
-- some operation
END IF;
Check this for an example: Example of using UPDATING

You could use the NEW and OLD pseudorecords and run a comparison of the values
if :NEW.COL3 <> :OLD.COL3 THEN ...

Triggers don't know anything about the statement that invoked them, so you'll have to use some kind of out-of-band signalling, e.g. change your application to set some globals in a database package, or use an application context.

Related

Oracle trigger exclude conditions

I am trying to create an Oracle trigger
CREATE OR REPLACE TRIGGER ACT_SESSION_AUDIT_TRIGGER
AFTER INSERT OR UPDATE
ON ACT_SESSION
FOR EACH ROW
DECLARE
BEGIN
if (:NEW.PROTOCOL='HTTP' or :NEW.PROTOCOL='SFTP') and :NEW.PRINCIPAL NOT IN ('AAA%', 'BBB%') then
INSERT INTO ACT_SESSION_AUDIT (PRINCIPAL,
CON_START_TIME,
DIS_END_TIME,
ADAPTER_NAME,
ADAPTER_TYPE,
PROTOCOL)
VALUES(:NEW.PRINCIPAL,
:NEW.CON_START_TIME,
:NEW.DIS_END_TIME,
:NEW.ADAPTER_NAME,
:NEW.ADAPTER_TYPE,
:NEW.PROTOCOL);
END if;
END;
However when the PRINCIPAL begins with AAA, it causes the trigger to be invoked. What is the correct way of using NOT IN with partial strings ?
You need LIKEfor the pattern matching in 'AAA%' and 'BBB%'.
IF :new.protocol IN ('HTTP', 'SFTP') AND
:new.principal NOT LIKE 'AAA%' AND
:new.principal NOT LIKE 'BBB%' THEN
...
You can move this to a WHEN cause by the way, to make this part of the trigger declaration part:
CREATE OR REPLACE TRIGGER ACT_SESSION_AUDIT_TRIGGER
AFTER INSERT OR UPDATE
ON act_session
FOR EACH ROW
WHEN (new.protocol IN ('HTTP', 'SFTP') AND
new.principal NOT LIKE 'AAA%' AND
new.principal NOT LIKE 'BBB%')
BEGIN
In theory this is faster, because the trigger won't get invoked, when the criteria is not met. I don't know, if this can really make a difference.

sql query inside if stage with exists

I want to check if the id I want to insert into tableA exists in tableB into an if statement
Can I do something like this
if new.id exists (select id from tableB where stat = '0' ) then
some code here
end if;
When I try this I get an error message, any thoughts?
Why not do it like this? I'm not very knowledgeable about PostgreSQL but this would work in T-SQL.
INSERT INTO TargetTable(ID)
SELECT ID
FROM TableB
WHERE ID NOT IN (SELECT DISTINCT ID FROM TargetTable)
This is usually done with a trigger. A trigger function does the trick:
CREATE FUNCTION "trf_insert_tableA"() RETURNS trigger AS $$
BEGIN
PERFORM * FROM "tableB" WHERE id = NEW.id AND stat = '0';
IF FOUND THEN
-- Any additional code to go here, optional
RETURN NEW;
ELSE
RETURN NULL;
END IF;
END; $$ LANGUAGE plpgsql;
CREATE TRIGGER "tr_insert_tableA"
BEFORE INSERT ON "tableA"
FOR EACH ROW EXECUTE PROCEDURE "trf_insert_tableA"();
A few notes:
Identifiers in PostgreSQL are case-insensitive. PostgreSQL by default makes them lower-case. To maintain the case, use double-quotes. To make your life easy, use lower-case only.
A trigger needs a trigger function, this is always a two-step affair.
In an INSERT trigger, you can use the NEW implicit parameter to access the column values that are attempted to be inserted. In the trigger function you can modify these values and those values are then inserted. This only works in a BEFORE INSERT trigger, obviously; AFTER INSERT triggers are used for side effects such as logging, auditing or cascading inserts to other tables.
The PERFORM statement is a special form of a SELECT statement to test for the presence of data; it does not return any data, but it does set the FOUND implicit parameter that you can use in a conditional statement.
Depending on your logic, you may want the insert to succeed or to fail. RETURN NEW to make the insert succeed, RETURN NULL to make it fail.
After you defined the trigger, you can simply issue an INSERT statement: the trigger function is invoked automatically.
Presumably, you want something like this:
if exists (select 1 from tableB b where stat = '0' and b.id = new.id) then
some code here
end if;

Updating value via trigger AFTER UPDATE Oracle 11g

I'm developing a small library database and I don't want to allow someone to update someone's ID. But I need to use AFTER UPDATE and FOR EACH STATEMENT (which I'm told is Oracle's default). So, basically, if someone updates the customer info and alter his/her ID or mistypes it, the trigger will automatically update it again to the old value. The problem is that Oracle won't let me use :NEW and :OLD when using FOR EACH STATEMENT. Are there any workarounds to this issue?
CREATE OR REPLACE TRIGGER alter_id_trigger
AFTER UPDATE ON CUSTOMER
BEGIN
UPDATE CUSTOMER SET ID = :OLD.ID
WHERE ID = :NEW.ID;
END;
Thank you!
Use the below code for trigger.
Changes done:
Using BEFORE UPDATE instead of AFTER UPDATE.
Setting the value of ID to what it was previously. (The ID Field would never be modified)
CREATE OR REPLACE TRIGGER ALTER_ID_TRIGGER
BEFORE UPDATE ON CUSTOMER
BEGIN
SET :NEW.ID = :OLD.ID
END;
Note: With BEFORE UPDATE:
You can not create a BEFORE trigger on a view.
You can update the :NEW values.
You can not update the :OLD values.
I think you want a before update trigger:
CREATE OR REPLACE TRIGGER alter_id_trigger
BEFORE UPDATE ON CUSTOMER
BEGIN
SET :NEW.ID = :OLD.ID
END;
You could test to see if the value is being changed, but that seems unnecessary.

SQL want to log values before and after update table

I have a problem here.
DB: oracle 9i
I want to save data changes after I execute UPDATE script on my table,
in that log I want to compare old values with new values.
How can i do this.
thanks for helping me :)
write simple trigger, by using :OLD and :NEW you can get the value of both new and old value of the table
create or replace
trigger tg_name
after UPDATE ON table_name
for each row
BEGIN
IF :NEW.column1 = :OLD.column1 THEN
-- any statement
END IF;
-- you can log the old and new value by inserting into log table's too..
END;
You can do a trigger on after update and you can use :old and :new values for each field you want.
In case, if you need only updated values you can use RETURNING clause.
like
UPDATE <table> SET (c1) = (v1), (c2) = (v2), (cn) = (vn)
WHERE <condition>
RETURNING <expression> INTO <variables>
http://psoug.org/definition/RETURNING.htm

how to write Instead of update? - Trigger

I have table A and there is a column name COL_A.
I want that if someone change the value, lets say from 1 to 'X' (not costant) that the trigger will change it back from 'X' to 1.
SQLite does not support changing the new column values.
The only way to change a column in a trigger would be to run an UPDATE command,
but that would run the trigger again.
What you can do is to prevent changing the column in the first place:
CREATE TRIGGER IF NOT EXISTS prevent_col_a_change
BEFORE UPDATE OF col_a ON a
BEGIN
SELECT RAISE(ABORT, 'COL_A must not be changed');
END;
UPDATE trigger is a good solution for your case. Just set old value to the new value, that will lead to behaviour you want.
For example:
CREATE OR REPLACE TRIGGER orders_before_update
BEFORE UPDATE
ON orders
FOR EACH ROW
BEGIN
:new.CreatedAt:= :old.CreatedAt;
END;