Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger for only changed values

Say we have 3 records in table: orig_tab

---------------------------------------------
|  PK  |  Name  |  Address  |  Postal Code  |
---------------------------------------------
|   1  |  AA    |  Street1  |   11111       |
|   2  |  BB    |  Street2  |   22222       |
|   3  |  CC    |  Street3  |   33333       |
---------------------------------------------

Now the data is changed:

---------------------------------------------
|  PK  |  Name  |  Address  |  Postal Code  |
---------------------------------------------
|   1  |  AA    |  Street1  |   11111       |
|   2  |  BB    |  Street2  |   44444       |
|   3  |  CC    |  Dtreet7  |   33333       |
---------------------------------------------

What client wants is the update records and only the updated columns (yes, I know it doesn't make any sense but they use some old system from 1970s and they want to do some logging etc.). So the reporting table should be like this:

---------------------------------------------
|  PK  |  Name  |  Address  |  Postal Code  |
---------------------------------------------
|   2  |        |           |   44444       |
|   3  |        |  Dtreet7  |               |
---------------------------------------------

This what I tried:

CREATE OR REPLACE TRIGGER vr_reporting_trigger
   AFTER UPDATE ON orig_tab
   FOR EACH ROW
BEGIN
IF inserting THEN
INSERT INTO rep_tab(pk, name, address, code)
  SELECT :new.pk, :new.name, :new.address, :new,code FROM DUAL
  WHERE NOT EXISTS (SELECT 1 FROM rep_tab WHERE pk = :new.pk);
UPDATE rep_tab t SET t.name = :new.name, t.address = :new.address, t.code = :new.code 
   WHERE t.pk = :new.pk;
ELSIF updating THEN
IF :new.pk <> :old.pk THEN
     UPDATE rep_tab t
        SET t.name = :new.name, t.address = :new.address, t.code =: new.code
      WHERE t.pk = :old.pk ;
  END IF;
  MERGE INTO rep_tab d
  USING DUAL ON (d.pk = :old.pk)
  WHEN MATCHED THEN
  UPDATE SET d.name = :new.name, d.address = :new.address, d.code =: new.code
  WHEN NOT MATCHED THEN
  INSERT (d.pk,d.name, d.address, d.code) VALUES (:new.pk,:new.name, new.address, new.code);
END IF;
END;

with this solution, I get:

---------------------------------------------
|  PK  |  Name  |  Address  |  Postal Code  |
---------------------------------------------
|   2  |  BB    |  Street2  |   44444       |
|   3  |  CC    |  Dtreet7  |   33333       |
---------------------------------------------

I know that it somewhere in insert claus in when updating statement but I can't figure out how to have this claus changed as per my requirement. Any suggestion?

Thanks in advance.

like image 465
Jaanna Avatar asked Jun 26 '12 05:06

Jaanna


People also ask

How you get a list of updated columns in SQL Server trigger?

SQL Server COLUMNS_UPDATED() Function for Triggers. This function is used to know the inserted or updated columns of a table or view. It returns a VARBINARY stream that by using a bitmask allows you to test for multiple columns.

How do you execute a trigger only when a specific column is updated SQL Server?

In SQL Server, you can create DML triggers that execute code only when a specific column is updated. The trigger still fires, but you can test whether or not a specific column was updated, and then run code only if that column was updated. You can do this by using the UPDATE() function inside your trigger.

Is it possible to create the following trigger before or after UPDATE trigger for each row?

A new column value can be assigned in a BEFORE row trigger, but not in an AFTER row trigger (because the triggering statement takes effect before an AFTER row trigger is fired). If a BEFORE row trigger changes the value of new .

What is the difference between trigger old and trigger new?

When a field value is changed to certain value, we use trigger.old and trigger.new to compare the older and new version values of the field values on a record and perform the required business logic accordingly. trigger.old is available only on the update and delete events. Considerations

How do I specify a column name in an update trigger?

In an UPDATE trigger, a column name can be specified with an UPDATING conditional predicate to determine if the named column is being updated. For example, assume a trigger is defined as the following: CREATE OR REPLACE TRIGGER ... ... UPDATE OF Sal, Comm ON Emp_tab ...

How to implement trigger conditions in power automate?

- Minimizing the flow runs for better flow performance Specifying trigger conditions in Power Automate. Let's consider the scenario shared above and we will try to implement a trigger condition for the same. Step 1: Open Power Automate --> Create Flows --> Automated from Blank, Select the trigger when an item is created and click on create.

When a field value is changed to a certain value we use?

When a field value is changed to certain value, we use trigger.old and trigger.new to compare the older and new version values of the field values on a record and perform the required business logic accordingly. trigger.old is available only on the update and delete events.


2 Answers

You need this:

In an UPDATE trigger, a column name can be specified with an UPDATING conditional predicate to determine if the named column is being updated. For example, assume a trigger is defined as the following:

CREATE OR REPLACE TRIGGER ...
... UPDATE OF Sal, Comm ON Emp_tab ...
BEGIN

... IF UPDATING ('SAL') THEN ... END IF;

END;

From Oracle documentation(9i)

11gR2 documentation

like image 69
Florin stands with Ukraine Avatar answered Nov 09 '22 13:11

Florin stands with Ukraine


Trigger for only changed values.

As an example (only NOT NULL support) (comparison operators with NULL always return FALSE):

CREATE OR REPLACE TRIGGER trigger_department_update
  BEFORE UPDATE OF 
      department_id,
      cluster_id, 
      division_id, 
      macroregion_id, 
      address, 
      email
    ON cl_department
  FOR EACH ROW
BEGIN
  IF (
    :new.department_id != :old.department_id
    OR :new.cluster_id != :old.cluster_id
    OR :new.division_id != :old.division_id
    OR :new.macroregion_id != :old.macroregion_id
    OR :new.address != :old.address
    OR :new.email != :old.email
  ) 
    THEN :new.update_date := CURRENT_TIMESTAMP; 
  END IF;
END;

With NULL support (Thanks to @Oleg in the comments below this post) (Thanks to @Chris Bandy for the answer):

CREATE OR REPLACE TRIGGER trigger_department_update
  BEFORE UPDATE OF 
      department_id,
      cluster_id, 
      division_id, 
      macroregion_id, 
      address, 
      email
    ON cl_department
  FOR EACH ROW
BEGIN
  IF (
    ((:new.department_id <> :old.department_id OR :new.department_id IS NULL OR :old.department_id IS NULL) AND NOT (:new.department_id IS NULL AND :old.department_id IS NULL))
    OR ((:new.cluster_id <> :old.cluster_id OR :new.cluster_id IS NULL OR :old.cluster_id IS NULL) AND NOT (:new.cluster_id IS NULL AND :old.cluster_id IS NULL))
    OR ((:new.division_id <> :old.division_id OR :new.division_id IS NULL OR :old.division_id IS NULL) AND NOT (:new.division_id IS NULL AND :old.division_id IS NULL))
    OR ((:new.macroregion_id <> :old.macroregion_id OR :new.macroregion_id IS NULL OR :old.macroregion_id IS NULL) AND NOT (:new.macroregion_id IS NULL AND :old.macroregion_id IS NULL))
    OR ((:new.address <> :old.address OR :new.address IS NULL OR :old.address IS NULL) AND NOT (:new.address IS NULL AND :old.address IS NULL))
    OR ((:new.email <> :old.email OR :new.email IS NULL OR :old.email IS NULL) AND NOT (:new.email IS NULL AND :old.email IS NULL))
  ) 
    THEN :new.update_date := CURRENT_TIMESTAMP; 
  END IF;
END;
like image 22
Maxim Mandrik Avatar answered Nov 09 '22 14:11

Maxim Mandrik