TRIGGER: Read NEW.values and OLD.values during "ON DUPLICATE KEY UPDATE" - mysql

I'm trying to write a mini-auditing system for individual tables in MySQL.
I had good luck working with basic INSERT/UPDATE/DELETE commands, however now a table I'm interested in auditing uses INSERT ... ON DUPLICATE KEY UPDATE.
By using a trigger ON BEFORE INSERT I can tell this event is occurring, however I can only get half the data I'm interested in. NEW.values are readily available, but I've no idea how to get the OLD.values that came before. I suppose I could do a query using the NEW.ID in existing table, but I'm not sure about performance and reliability.
I need the OLD.values because I'm storing both old and new values for each change event since I read somewhere that was a good idea for collapsing data etc...
Is there a way in MySQL 5.0 (or newer GA release) to reliably retrieve these values as though I were in an UPDATE trigger?
EDIT: Another wrinkle:
Looks like the NEW.values do not match the data after update. They match the INSERT statement not the ON DUPLICATE KEY UPDATE data that will actually go into the record.

It looks like the trigger event ON AFTER UPDATE also catches the ON DUPLICATE KEY UPDATE change. From here, I was able to get OLD/NEW values and perform the logging I needed to perform.

Related

Duplicates data after joining trigger table with other tables

I want to fetch the BEFORE and AFTER data from TableProduct whenever there is an update. So I created a Before and After trigger queries in which the respected values from the trigger is stored in separate tables titled TableProduct_Before and TableProduct_After.
My challenge is I always get duplicates result whenever I try to INNER JOIN the three tables.
I have tried the DISTINCT and ORDER BY ID command but still the same challenge.
I made enquiry I was told I can't join trigger table values because it doesn't have a foreign key, I tried adding a foreign key but it didn't work saying foreign key already exists in TableProduct.
Please, I will appreciate any help thank you.
You are misunderstanding how triggers work. You can use either a before or after trigger.
The key is using new and old. Inside the body of the trigger, you have both the old and new values. In pseudocode, this looks like:
insert into archive (pk, old_value, new_value)
values (new.pk, old.value, new.value);
Both OLD and NEW data is available in both before and after trigger.
The difference is - BEFORE trigger fixes the attempt to update whereas AFTER fixes successful attempt result. I.e. BEFORE is executed anycase (but its changes may be rollbacked!), rather than AFTER.
See https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=dd19c611c7e2fbef88b2133dcaa61dfa
PS. Recent MySQL versions allows triggers chains - a lot of triggers on the same event fired one-by-one. So check that your saving trigger is the most last in this chain.

Why not to delete tho old row and insert updated row?

I have a table (MySql) that some rows need to be updated when a user desires.
i know the right way is just using Sql UPDATE statement and i don't speak about 'Which is faster? Delete and insert or just update!'. but as my table update operation needs more time to write a code (cause of table's relations) why i don't delete the old row and insert updated field?
Yes, you can delete and insert. but what keeps the record in your database if the program crash a moment before it can insert data to Database?
Update keeps this from happening. It keeps the data in your database and change the value that needed to be changed. Maybe it is complicated to use in your database, but you can certain that your record still safe.
finally i get the answer!
in a RDBMS system there are relations between records and one record might have some dependencies. in such situations you cannot delete and insert new record because foreign key constraint cause data lose. records dependent (ie user posts) to main record (ie an user record) will be deleted!
if there are situations that you don't have records dependencies (not as exceptions! but in data models nature) (like no-sql) and you have some problems in updating a record (ie file checking) you can use this approach.

Multiple insert in mysql table, some of which may be repeated

I'm developing a php script in which I insert multiple data into a mysql table, but some of this data may already be inserted. I can try to insert each of the individual data and detect the #1062 error (duplicate entry), but it would be very inefficient since it can be more than 100 entries. So, is there any way to do this in one query or must I use a query for each entry to be inserted?
Thanks a lot.
You'll want to use the INSERT ... ON DUPLICATE KEY UPDATE command to accomplish this. In the "ON DUPLICATE KEY UPDATE" section, you can just do some kind of update that changes nothing. For example, "SET fieldName=fieldName", just so nothing is actually changed.
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Restore DB from SQL script with Foreign Key Constraints

I am trying to restore a DB using an SQL script, but things foreign key constraints get in the way
I am taking a MySQL DB and bringing it over to PostgreSQL.
Since the MySQL create table syntax ended up being quite different, I took another PostgreSQL DB with the same schema, but different data and restored the schema only, from that.
In other words, I now have a database with tables, constraints, sequences and all that shnaz but no data inside.
So, it's is time to restore data.
I take a backup of the MySQL DB with phpMyAdmin (data only) as an SQL script (pgAdmin does not seem to accept zip or gzip files for some reason) and run the SQL script.
Now, this is where the problems start to happen, it's only natural, I am going from MySQL to PostgreSQL, so syntax errors are bound to happen.
But, there are other non syntax related problems to, like this one:
ERROR: insert or update on table "_account" violates foreign key constraint "fk_1_account"
DETAIL: Key (accountid)=(2) is not present in table "_entity".
So, yeah, basically, a foreign constraint exists, the query is trying to insert data into the _account table, but the corresponding data has not been inserted into the _entity table yet.
How do I get around that? Is there a way to make pgAdmin3/PostgreSQL disable ALL OF the constraints, insert the data, and then re-enable the constraints?
A syntax related error I encountered, was this one:
INSERT INTO _accounttype_seq (id) VALUES (11);
The PostgreSQL equivalent of that statement (if I am correct) is
ALTER SEQUENCE _accounttype_seq INCREMENT BY 11;
But, it's a bit of a pain to run through the whole script and change all 200+ Sequence insert statements. So, I am being lazy here, but is there an easier way to deal with the sequences as well?
Or, do you guys have any suggestions for a different set of tools to make this easier?
Thanks for your time, have a good day.
Do not try to get around the foreign key constraints. That is the way to make sure the data is bad.
First look at the constraints and make sure you are inserting to the tables in the correct order. If _entity is parent of "_account, then it should be populated first.
Next you need to have the script move any failing records to an exception table. Then you can look at them and see what the data integrity issues is and if you need to throw the records away permanently or try to figure out what the missing parent value should be. If it is critical data such as orders where the customer no longer exists (possible in any system that didn't have correct fks to begin with) and you must keep the record and cannot determine what the parent value should have been, you can create an 'Unknown" record in the customer table and assign all bad orders to that customer id.
And manually changing the alter sequences shouldn't take long even if it is boring. There wil be plently of other things you need to handle manually in a conversion of this type.
I would try to find a data import tool for PostgreSQL - I live in SQL server world where I would use SSIS but you need the equivalent of SSIS for the PostgreSQL world.
Aparently the foreign keys weren't actually enforced in MySQL (maybe because of using MyISAM) or the generated SQL just does it in the wrong order.
If it's "only" the wrong order, I see two possible solutions:
edit the generated script and either move all FK definitions to the end of the script
Edit the definition of each FK constraint and set them all to initially deferred. Then run the script as one single transaction with only on commit at the very end.
Edit (because this is too much to be put as a comment)
Using SET CONSTRAINTS ALL DEFERRED will only work if the constraints have been created with the option DEFERRABLE.
To run everything in one single transaction, you have to make sure you have turned autocommit off. Then simply run the INSERTs and at the very end issue a COMMIT. A ; will only commit if you have autocommit on.
If you want to be independent of the autocommit setting, then start your script with [BEGIN][1] and make sure there is only a single COMMIT at the very end.
BEGIN DEFERRABLE
INSERT INTO table_one ... ;
INSERT INTO table_two ... ;
.....
COMMIT;

Sql Trigger to insert updated record into another table

i've been looking though different tutorials online,but i can't seem to find what i need.
I need to copy a record into a history table, every time it is updated.
Is there a way to do it with triggers without having to type out all of my data fields?
It would help if you posted a schema of your tables, and what exactly you want to be inserting into your history table, but for now I'll make some assumptions about the table you're updating, and what you want in your history table. As an aside, this trigger will not work for a copy-paste... as each subsequent update to a record will be unable to be inserted into your history table because of primary key violations.
CREATE TRIGGER trg_History AFTER UPDATE ON my_table
FOR EACH ROW INSERT INTO history_table VALUES (NEW.col1, NEW.col2, OLD.col1, OLD.col2 ... etc)
the NEW keyword refers to all the data being inserted/updated and OLD refers to, well, the old data before being overwritten.
Again, please be more specific with the information you need to be inserting, and what you've tried so far, as we can only help you with general syntax at this point in time.