SQL Trigger not on rows but on attributes - mysql

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.

Related

Am I using too many triggers within mySQL database?

I had a problem within my database where clients would update their information on the website, and the update would overwrite their original information in the database. To have a record of the clients previous information and when they updated it to the 'new' information, I have created a trigger for the specific database.
Example:
CREATE TRIGGER clientstatustrigger AFTER UPDATE ON clientstatus
FOR EACH ROW
BEGIN
INSERT INTO clientstatusrecord SET id = NEW.id, oldstatus = OLD.status, newstatus = NEW.status, timechanged = NOW();
END;
It has worked really great so far! However, I will need to implement this technique for a lot of tables. I will be creating a "record" table for each table I need to track the changes within, and one trigger for those tables. My question is, is this too many triggers? Will I see disadvantages in the future? I understand triggers are hard to debug since people forget they are there, but is there reason for me to change this system? If so, what do you recommend?

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.

Create a row in another table based on currently inserted row

I think that there was a way that by not making two INSERT statements we could add a row on another table. I don't know if it was about CASCADEing or not but didn't find anything based on the keywords (wrong maybe!) I used.
Currently I've two tables, one is users and the other is data, when a user is created I want a row in data table get added so in this way I can update it later. data columns are all nullable except the uid which is user id on data table -Unique- that respectfully lives in id column of users table.
Any help is appreciated.
Thanks to the guys that triggered me to use a TRIGGER. I wasn't familiar with them at all!
Here is the Trigger, as simple as possible, for the later visitors of this topic:
DELIMITER $$
CREATE
TRIGGER `user_after_insert` AFTER INSERT
ON `users`
FOR EACH ROW BEGIN
INSERT INTO data (uid) VALUES (NEW.id);
END$$
DELIMITER ;
I don't recommend reading docs if you're a newbie in them like me but this page that will help you unserstand more with some examples!

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.

To check values in other databases using trigger

Is it possible to check whether a particular value in a column exists in other databases using trigger? These two databases are located inside the same MYSQL instance. Specifically, what I want to do is this:
Before a row is added to a table ( Document_Index_table) inside Database A ( Document_DB).
A trigger is fired. This trigger carries the one of the column value (usr_id) inside the row and pass it to Database B ( User_Control_DB).
Based on the values, User_Control_DB will check whether the usr_id exists in column usr_id of the table (Usr_Information).
If exists, then return a true to Document_DB and the row in 1. is allowed to add to the Document_DB.
If not, then an error is issued. No row is added to Document_DB.
How can this be done, if it can be done at all?
Edit: Both databases are MySQL databases
So, I'm a complete novice at database development, but you could do something like this:
Create a 'Before' insert trigger on your document_index_table.
The trigger does something like this:
declare numRows integer;
select count(*) from user_control_db.usr_information where usr_id = NEW.usr_id into num_rows;
if (numRows > 0) then
call NonExistentProc();
end if;
I believe that this would accomplish what you wanted. It'll produce an error like "PROCEDURE documentdb.NonExistenProc does not exist" and skip the insert if there isn't at least one row that has the matching usr id in the user control db.
Again, I'm a novice at this DB stuff so there might be a more elegant way, but this worked for my single test case.
Hope that helps.