MySQL Trigger - INSERT on condition of UPDATE - mysql

I'm trying to find the most effecient way of inserting data into another table when a particular field is updated on trigger table. The INSERT should only occur on a specific type of update.
The table on which I want to create the trigger is named incremental. The table I'm inserting into is named crm_record
On incremental there is a field called status. By default when a record is initially added to the table the status field is set to new. After billing has processed that value changes to processed. So once this occurs I want to INSERT into crm_record, only if the value of another field (success) is set to 1.
I have considered using both CASE and IF but would like an expert's opinion on the best way to do this.

Ok, I eventually went with this that seemed to work. Thanks for pointing me in the right direction
CREATE TRIGGER `incremental5_after_ins_tr_crmm` AFTER UPDATE ON `incremental5`
FOR EACH ROW
BEGIN
IF Status = 'processed' AND Success = 1 THEN
INSERT INTO crm_master (msisdn,source,contract_type,revenue) VALUE (new.msisdn,'INC5',new.contract_type,revenue=revenue+2.5)
ON DUPLICATE KEY UPDATE contract_type=new.contract_type,revenue=revenue+2.5;
END IF;
END;

All you need to do is to create an AFTER UPDATE trigger and test the value of status and success together. If it's going only going to be one state you're testing for then an IF statement would be the simplest way to go about it.
However before implementing a trigger it's always worth going back a step and checking to see if the row in crm_record shouldn't actually be inserted via the code logic when the status and success columns are updated.

Related

SQL Trigger to update OLD value in another table

I am trying to create a trigger to simultaneously update a different table than the one I have updated, with the same data.
I have two different database with the same tables and i'm trying to sync them, when i insert, update or delete data from one, i want to do automaticaly the same to the other table, with triggers.
This is the trigger code:
CREATE DEFINER=`Ivan_test`#`%` TRIGGER `Prueba_Ivan`.`mag_articulos_PI_AFTER_UPDATE` AFTER UPDATE ON `mag_articulos_PI` FOR EACH ROW
BEGIN
IF OLD.Prueba_Ivan.mag_articulos_PI NOT IN (SELECT * FROM ivan_test.mag_articulos_IT) THEN
INSERT INTO ivan_test.mag_articulos_IT
VALUES (new.xempresa_id, new.xarticulo_id, new.xcategoria_id, new.xvisible_web, new.xnovedad,new.xpromocion,new.ximagen_prelim,new.ximagen_amp,new.xtexto1,new.xtexto2,new.xtexto3,new.xtexto4,new.xtexto5);
ELSE
UPDATE ivan_test.mag_articulos_IT SET OLD.ivan_test.mag_articulos_IT = NEW.Prueba_Ivan.mag_articulos_PI;
END IF;
END
but I have this error:
Error Code: 1109. Unknown table 'OLD.Prueba_Ivan' in IN/ALL/ANY subquery
Can someone help me to find the mistake?
Thank you!!
OLD.Prueba_Ivan.mag_articulos_PI
OLD is an alias to the triggered row. Your trigger applies to Prueba_Ivan, which means that OLD and NEW are representing your Prueba_Ivan record before the change, and after it, respectively. This means that when you intend to reference mag_articulos_PI, you will need to do it via OLD.mag_articulos_PI, so remove the tablename from that expression.
OLD.ivan_test.mag_articulos_IT
As mentioned in the previous section, here OLD is an alter-ego of the updated Prueba_Ivan record, you do not need it in order to reference ivan_test.
Further explanation
An expression of the form of
a.b.c
reads as follows:
In database a, table b, column c. When you do something of the like of
OLD.t.c
it reads: In the OLD database, table t, column c.

SQL Trigger not on rows but on attributes

Hey guys a little question for you.
I'm currently working on SQL Triggers and my goal is to archive logging if there are changes made to our database. For example we got some tables like customers with: name, firstname, placeofbirth and so on. We offer the users to update their own data and want to save the OLD data in a new table for logging reasons. To have only one logging table for all updates the logging table is kind of generic with:
id, timestamp, table_name, column, old_value, new_value.
table_name is the updated table, colum the updated column in this table and all the rest should speak for itself. Therefore it would be great to know not only in which tuple but also in which particular column the update has happened.
My question: Is there a construct like:
create trigger logging_trigger on customer**.firstname** after insert ...
to trigger an action only if there happened an update on let's say the 'firstname' column?
If not is there a smooth solution for handling all possible update cases?
Thank you.
I use a format like you described in my system... Below is how I accomplish it with your required logic.
CREATE DEFINER = CURRENT_USER TRIGGER `testing_schema`.`new_table_BEFORE_UPDATE` BEFORE UPDATE ON `new_table` FOR EACH ROW
BEGIN
IF NEW.ColumnName <> OLD.ColumnName THEN
INSERT INTO HistoryTable (`ColumnName1`, `ColumnName2`, ect..) VALUES (OLD.ColumnName1, OLD.ColumnName2, ect...);
END IF;
END
The main difference In mine is, that I do not have an IF condition. I simply copy the entire row to the history table every time an Update/Delete is made to that row. That way I don't have to maintain any form of logic to handle scenarios of investigating "what changed", I just save the entire row because I know "something" changed.

What is proper way to set and compare variable inside an sql trigger

Am populating a table using a trigger after an insert event occurs on another table and that worked fine. However i then noticed that the trigger would still insert a new row for existing records. To fix this, I want to create the trigger again but this time it would only fire if a condition is met...but not having previously used triggers in the past am getting a syntax error and not able to identify what am doing wrong. Kindly have a look and help me fix this
CREATE TRIGGER `students_gen_insert`
AFTER INSERT ON `students` FOR EACH ROW
BEGIN
INSERT INTO records (student_id, subject_id)
SELECT new.student_id, subjects.subject_id
FROM subjects
WHERE category = new.class;
END;
Am currently using MySql 5.6.17 version.
It is generally not a good idea to SELECT from the table the trigger is on, and forbidden to UPDATE or INSERT (not that you are doing those). Assuming you are trying to get the values for the row just inserted, the first SET ... SELECT you have is needless; just use NEW.fieldname to get the fields of the inserted row.
The second SET ... SELECT and following condition are a bit confusing. If referential integrity is being maintained, I would think it would be impossible for the records table to refer to that particular student_id of the students table at the point the trigger is executed. Perhaps this was to avoid the duplicate inserts from the trigger's previous code? If so, it might help for you to post that so we can pinpoint the actual source of redundant inserts.

UPDATE Same Row After UPDATE in Trigger

I want the epc column to always be earnings/clicks. I am using an AFTER UPDATE trigger to accomplish this. So if I were to add 100 clicks to this table, I would want the EPC to update automatically.
I am trying this:
CREATE TRIGGER `records_integrity` AFTER UPDATE ON `records` FOR EACH ROW SET
NEW.epc=IFNULL(earnings/clicks,0);
And getting this error:
MySQL said: #1362 - Updating of NEW row is not allowed in after trigger
I tried using OLD as well but also got an error. I could do BEFORE but then if I added 100 clicks it would use the previous # clicks for the trigger (right?)
What should I do to accomplish this?
EDIT - An example of a query that would be run on this:
UPDATE records SET clicks=clicks+100
//EPC should update automatically
You can't update rows in the table in an after update trigger.
Perhaps you want something like this:
CREATE TRIGGER `records_integrity` BEFORE UPDATE
ON `records`
FOR EACH ROW
SET NEW.epc=IFNULL(new.earnings/new.clicks, 0);
EDIT:
Inside a trigger, you have have access to OLD and NEW. OLD are the old values in the record and NEW are the new values. In a before trigger, the NEW values are what get written to the table, so you can modify them. In an after trigger, the NEW values have already been written, so they cannot be modified. I think the MySQL documentation explains this pretty well.
Perhaps you could write two separate statements in that transaction
update record set clicks=...
update record set epc=...
or you could put them inside a function, say updateClick() and just call that function. By doing it this way you can easily alter your logic should the need arise.
Putting the logic inside a trigger might create a situation where debugging and tracing are made unnecessarily complex.

Last Inserted Row info without Auto-Incrementing PK

I've got a number of tables that "share" a single auto-incrementing primary key - this is accomplished via a trigger on insert which looks like this:
FOR EACH ROW
BEGIN
INSERT INTO master (time) VALUES (NOW());
SET NEW.id = LAST_INSERT_ID();
END
This produces the PK for the just inserted row. This does, however, create the problem that I can't seem to figure out what that ID was. last_insert_id obviously returns nothing as the above statement wasn't executed on what's considered "the current connection".
Is there a way to access the most recently inserted row on a connection without an auto-incrementing primary key?
Update: As a temporary(?) measure I've removed the trigger and now generate the ID by making the insert to master within my model. Just seems like it would be nicer if I could somehow return the value that the trigger set.
The doc does say, "For stored functions and triggers that change the [LAST_INSERT_ID] value, the value is restored when the function or trigger ends, so following statements do not see a changed value."
Try a stored procedure, which can do your two INSERTS and return the assigned ID.
Or, give up on doing things the "Oracle way", drink the MySql Kool-Aid, and just use an auto-incrementing id on the table.