Friday, April 28, 2006

Migrating triggers from SQLServer to MySQL

After a few posts on Devshed forums I decided to summarize some basic directions about porting SQLServer triggers to MySQL.
There are some notable differencies between trigger syntax in SQLServer and MySQL (and other databases in general).
First of all usually you reference old (preexisting) and new (inserted or updated) column values by NEW.column_name and OLD.column_name, but in SQLServer those values are held in two tables named INSERTED and DELETED, on which you'll have to perform selects.
Second relevant difference is that SQLServer doesn't have BEFORE triggers, you'll have to use a rather convoluted syntax for this.
Third difference is that one SQLServer trigger can fire upon multiple actions (one single trigger for insert/update/delete).
Fourth difference, as new/old values are held in a table there is no FOR EACH ROW implicit loop but you'll have to loop through the table values with a cursor (or process records in a block through a DML statement).
Here are two examples:

First is a SQLServer trigger that converts a string into uppercase before inserting.

  1. CREATE TRIGGER upper_all
  2. ON test_table
  3. instead of INSERT
  4. AS
  5. INSERT INTO test_table (a_field) SELECT UPPER(a_field) FROM INSERTED;

Note that the trigger will fire upon insert cancelling the original insert and doing an alternate insert which converts into uppercase the value of a_field column.
The same in MySQL would be:

  1. DELIMITER $$
  2. DROP TRIGGER test.upper_all$$
  3. CREATE TRIGGER upper_all before INSERT ON test_table
  4. FOR EACH ROW
  5. BEGIN
  6. SET NEW.a_field = UPPER(NEW.a_field);
  7. END$$
  8. DELIMITER ;

IMHO this syntax is simpler and clearer.
Another example:

  1. CREATE TRIGGER [mDBpush_Authors] ON [Authors] FOR INSERT, UPDATE,
  2. DELETE AS
  3. IF NOT EXISTS (SELECT * FROM INSERTED) -- "inserted" table is empty so must be delete trigger
  4. INSERT INTO mDBpkstub (TransTime,PK,LayerName,Type,STATUS)
  5. SELECT GetDate(),au_id,"Authors",3,0 FROM deleted
  6. ELSE IF NOT EXISTS (SELECT * FROM DELETED) -- "deleted" table is empty so must be insert trigger
  7. INSERT INTO mDBpkstub (TransTime,PK,LayerName,Type,STATUS)
  8. SELECT GetDate(),au_id,"Authors",2,0 FROM inserted
  9. ELSE -- both tables have entries so must be update trigger
  10. INSERT INTO mDBpkstub (TransTime,PK,LayerName,Type,STATUS)
  11. SELECT GetDate(),au_id,"Authors",1,0 FROM inserted

This trigger fires for inserts/updates and deletes thus has to check which of the three events is causing it to fire and act accordingly.
In MySQL you'll be required to create three triggers, each firing before action, an example (BEFORE UPDATE) is:

  1. DELIMITER $$
  2. DROP TRIGGER test.mDBpush_Authors$$
  3. CREATE TRIGGER mDBpush_Authors BEFORE UPDATE ON Authors
  4. FOR EACH ROW
  5. BEGIN
  6. SET NEW.TransTime = now();
  7. -- PK field (au_id) comes from the update statement, no need to change it
  8. SET NEW.LayerName = "Authors";
  9. SET NEW.Type = 1;
  10. SET NEW.STATUS = 0;
  11. END$$
  12. DELIMITER ;


Hope this helps!
More on this here and here.

No comments: