How to set a MySQL Trigger the correct way - mysql

i have a database table that gets updated via a CMS. Sometimes, there is one field that gets updated and then another field should get updated as well. I tried to get this done by just modifying the php code of the CMS, where the value gets saved in the DB. The problem is, with every update of the CMS this is gone.
I came across MySQL Triggers and i think this is a good way to do this. So whenever this field is updated, it should also update the other field with a value that will always be the same. But i cant quite get my head around the syntax, to get this going...
I tried:
CREATE TRIGGER after_unique_content_update
AFTER UPDATE
ON articles FOR EACH ROW
BEGIN
IF OLD.date <> new.date THEN
INSERT INTO release=2020
END IF;
END
But it is not working. So what i try to do: Every time in the CMS someone changes the date, the release for that db entry should be set to 2020. The standard for release is NULL. With the above trigger, nothing happens after the date is changed... Never worked with Trigger or Events in MySQL before...
How can i set the release to 2020 when the date field for that entry is updated?
Thanks for your help in advance!
best regards

CREATE TRIGGER before_unique_content_update
BEFORE UPDATE
ON articles
FOR EACH ROW
SET NEW.release = CASE WHEN OLD.date <> NEW.date
THEN 2020
ELSE NEW.release
END;
Firstly the condition is checked by the trigger, and, if the condition matched, new value to the column is set to 2020 (or, maybe, it's better to set it not to 2020 but to YEAR(CURRENT_DATE)?). If the condition not matched then the value is not altered (assigned value is the same as current one).
After the trigger performs this task, actual table data update is performed.
AFTER UPDATE trigger is not applicable - when it fires the data in the table is already set to the value specified in a query.

Related

MySql cannot update a DATETIME field - no record found

I have a table in MySql 5.6.10 defined as this:
When I do a select query (from HeidiSQL client) for a particular record filtering on the id_failed_delivery_log column, the record is found successfully, but when I use the same filter for the UPDATE command, then no record is found and no error reported:
When I update a different column using the same filter, the update works and I can see the updated value. Then there is an issue with an update to this particular column.
I've also tried updating with a time function instead of hard-coded date value, for example with the now() function but I still get the same result and the record is not found.
Could it be caused by the 'Default' value is set to CURRENT_TIMESTAMP?
After further investigation I found the reason why I couldn't update that field. I was not totally familiarized with the database definition and I found that there was a trigger in the same schema that forced to keep the date_created column with the same value:
SET #OLDTMP_SQL_MODE=##SQL_MODE, SQL_MODE='STRICT_ALL_TABLES';
DELIMITER //
CREATE TRIGGER `failed_delivery_log_before_update` BEFORE UPDATE ON
`failed_delivery_log` FOR EACH ROW BEGIN
SET NEW.date_created = OLD.date_created ;
END//
DELIMITER ;
SET SQL_MODE=#OLDTMP_SQL_MODE;
I removed this trigger temporarily in order to test. Once removed, the updated worked fine. The trigger execution was not reported in the SQL client, so it was difficult to find out its execution.

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.

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.

Update mysql table with same values and still get a timestamp update

So I have this stamp timestamp DEFAULT NOW() ON UPDATE NOW() row on my table, and I need it to update even when the update I'm executing is basically same data on all fields.
Is there any way of doing this within the declaration of the table, like some other option other than on update, or do I have to force a stamp = now() every time I update (and remove the on update of course since it will be useless).
I've seen this thread, but it only answers what is happening and why, not how to get around it other than forcing it indirectly
As #veeTrain said, it'd be easy if you added it to your update statement. This is just another way of doing it, you can also use unix_timestamp().
UPDATEtable_nameSETlast_logged_in= unix_timestamp() WHEREid= '$user_id'
I know my response is late, but I ran into a similar issue and figured I'd share my solution for those encountering this thread in the future.
You'd have to use a trigger to force it each time.
DELIMITER GO
CREATE TRIGGER `mydb`.`mytable_U` BEFORE UPDATE ON `mydb`.`mytable`
FOR EACH ROW
BEGIN
SET NEW.stamp = CURRENT_TIMESTAMP;
END
GO
DELIMITER ;
I find it easier to just do the following as part of your update statement:
UPDATE table_name SET last_logged_in = NOW() WHERE `user_id`...
This way the value is always updated and if nothing else has changed the timestamp still gets updated. Thanks for your question; it was the same as mine.

MySQL Trigger - INSERT on condition of UPDATE

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.