Updating MySQL fields only when other information in the row changes - mysql

I have a problem where I would like a field to work in a similar way to the timestamp type field, where it only gets updated on an update if there are other changes to the record.
I am using php to update a mysql database with myisam tables.
Take the following example table which has one row with the following fields;-
UNIQUEID : 1
TITLE : Example
AMENDAT : (timestamp)
AMENDBY : Andy
I have some code which handles maintenance on the table. The update to the table uses (for example) the following statement ;-
update example set TITLE="New Title",AMENDBY="Andy" where UNIQUEID=1 ;
This statement works fine and updates the row including the AMENDAT timestamp field.
If a different user makes the same change;-
update example set TITLE="New Title",AMENDBY="Bob" where UNIQUEID=1 ;
Again, everything works as expected.
But, it is possible that the update statement may be called when no changes have been made to any of the columns in the statement (this is possible in the real world because I have a large number of fields in the table which are all updated at once and I do not wish to code a check on the before and after values of the fields - I just let the update take the strain);-
update example set TITLE="Example",AMENDBY="Andy" where UNIQUEID=1 ;
In this case, MySQL decides that nothing need be done, so it does not update the AMENDAT timestamp (all good so far).
But if another user does the same thing;-
update example set TITLE="Example",AMENDBY="Bob" where UNIQUEID=1 ;
Then the row is updated due to the change in the AMENDBY field. So even though the actual data has not changed, the amendment details have (which is not good for my amendment tracking).
My current work around for this problem is to use the following statement for updates;-
update example set TITLE="XYZ",AMENDBY="XYZ",AMENDAT=NULL where UNIQUEID=123 ;
This forces an update every time, so the amendment details will reflect the last user to save the record whether or not they made any changes. Obviously this is not ideal.
Is there any way of making the AMENDBY field update only when there are changes to other fields on the record, much like the default functioning of a timestamp type field?
I realise this problem is easily solved by making two separate calls to MySQL, one to do the update and check from the return (number of records updated) whether to make a second call to update the amendment details, but this is a messy and not very elegant solution.
Bear in mind that I have a large number of tables which are set up in the same way, each has an arbitrary number of fields, so I don't want a solution which requires an enormous call to MySQL which includes an if statement for every field which may or may not be updated.

I think that what you are trying to do can be achieved with a TRIGGER with timing AFTER on the UPDATE event. Triggers can be tricky though, use them with extra caution. Also bear in mind, that if the trigger statement fails for some reason the actual UPDATE/INSERT/DELETE fails too.

Related

MySQL Faster Rand

I have a VIEW (view1) that returns random values from another table (Table2) based on values inside Table1.
A trigger is configured to UPDATE a third table (Table3), when values inside Table1 change. The purpose of Table3 is to hold the random values so they don’t get updated all the time.
The problem I have is that each select statement inside the trigger causes the whole row to get new random values for each column being updated. If there are multiple updates than it’s multiple times the whole row is getting new random values. I have adequate hardware, but it’s still too slow. Is there a way to reduce it, so maybe it selects once for each row, regardless of how many columns are receiving the updates? Maybe holds the values somewhere temporarily and updates from that?
Here is sample fiddle. In my real data I have significantly more columns.
Fiddle Example:
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=4fd8bf89135d8babe8c19fc15a565d50
Currently I don’t have indexes on any columns. I’ve read mixed reviews re indexes and updates.
Lastly, while browsing Stack I found a few links to this: https://jan.kneschke.de/projects/mysql/order-by-rand/, but I’m not sure there is a way I can apply it.

[MySQL]Insert a value depending on a condition

I'm studying MySQL so I'm a bit new to all this stuff, but the last time I asked you guys, you proved to be really helpful, so perhaps you can help me again because I haven't been able to find the answer on my own.
Ok, so the thing is, I need to add a new column to an already existing table, and it should be like:
ALTER TABLE `medicos`
ADD COLUMN `tipo_medico` VARCHAR(20) NOT NULL DEFAULT 'indiferente' AFTER `sueldo`;
Now I'm supposed to run an INSERT instruction to add the data there. After adding that column, the table looks like this:
These values equal to: Medic_number, Surnames, Speciality, Day of birth, University, Wage and Medic_type (the new column I've added). The data I add on all the columns except the last one doesn't really matter, but the last column must be filled following the next conditions:
-By default, it'll be "indiferente" (that's working).
-If a medic has studied in an university ending in -a (i.e. Valencia), it'll say "Excellent".
-If a medic is 40 years old or older, it'll say "Expert".
Now, I know how to do these conditions ("... university like = '%a'", etc), but I don't know how to add that into the INSERT instruction. This is what I've gotten so far:
insert into medicos values ('A021', 'Apellidos :D', 'Loquesealogia', '1970-03-14', 'Valencia', '3500');
That adds everything but the last column, which is the one where I'm lost. What can I do to tell the INSERT instruction to, depending on which of the previously named conditions are true, add one value or another?
I hope I've been clear enough, I'm not a native English speaker so I'm sorry if that wasn't good enough. Also I've tried to format the codes this time, I hope that'll work.
Thanks.
This seems to be a case when we need to apply a logic on column values before a record is inserted. I would suggest creating a BEFORE INSERT trigger on this table, which will be automatically executed by MySql before each record is inserted.
We can write the logic to determine the value of last column depending upon values supplied for the other columns. Have a look at this link for trigger example.
If the requirement here is to do a one time bulk insert then, we can drop this trigger once insertion is complete.
I would advise you to do it either with BEFORE INSERT trigger as Darshan Mehta recommends, or do your logic in the programming side, or with a stored procedure.
Still it is doable at query time, so to answer your question specifically, try something like this:
INSERT INTO medicos (num_colegiado, apellidos, especialidad, fecha_nac, universidad, sueldo, tipo_medico) SELECT 'A021', 'Apellidos :D', 'Loquesealogia', '1970-03-14', 'Valencia', '3500', IF('Loquesealogia' like '%a','Excellent',IF(DATE_ADD('1970-03-14', interval 40 YEAR)>NOW(),'Expert','indiferente'))

How to best check if a SQL table contents have not changed?

Assuming I have the following table named "contacts":
id|name|age
1|John|5
2|Amy|2
3|Eric|6
Is there some easy way to check whether or not this table changes much like how a sha/md5 hash works when getting the checksum for a file on your computer?
So for example, if a new row was added to this table, or if a value was changed within the table, the "hash" or some generated value shows that the table has changed.
If there is no direct mechanism, what is the best way to do this (could be some arbirary hash mechanism, as long as the method puts emphasis on performance and minimizing latency)? Could it be applied to multiple tables?
There is no direct mechanism to get that information through SQL.
You could consider adding an additional LastModified column to each row. To know the last time the table was modified, select the maximum value for that column.
You could achieve a similar outcome by using a trigger on the table for INSERT, UPDATE and DELETE, which updates a separate table with the last modified timestamp.
If you want to know if something has changed, you need something to compare. For example a date. You can add a table with two columns, the tablename and the timestamp, and program a trigger for the events on the table you are interested to control, so this trigger will update the timestamp column of this control table.
If the table isn't too big, you could take a copy of the entire table. When you want to check for changes, you can then query the old vs. new data.
drop table backup_table_name;
CREATE TABLE backup_table_name LIKE table_name;
INSERT INTO backup_table_name SELECT * FROM `table_name`;

How to mark posts as edited?

I would like to have questions marked as "Edited", but I dont know what the best way to do this would be.
Users post a question, people answer/comment on the question, and if necessary the user edits/updates the question (just like SO). I would like to note that the user edited the question, but I'm not sure of the best way to do this.
I was going to add a last_edited column in the table (because thats all thats really important to me), but I'm not sure if I should just split the edit times (and whatever else) into another table and record everytime the question gets edited.
EDIT: UIf I were to use a timestamp, what time would be used? Is there any way to insert a unix timestmap on update?
This depends on whether anyone (users or admins) ever cares about history of edits.
If they do, definitely split into another table
If all what you want is a mark Edited or not, you can just add a Timestamp column in the same table, populated to NULL by default, then populated by last update timestamp.
On the page if its populated then display its value, otherwise don't display the Edited icon/symbol.
If you only care about when the most recent update occurred, add a timestamp column in the same table.
If you'd like to keep track of every edit that's occurred, create a separate table that contains question_id and the timestamp.
Depending on how you're processing your date/time data, you can either store the unix time stamp (fieldname = unix_timestamp(now())), or as a regular mysql datetime field (fieldname=now()).
If you're going to do data sorting/filtering based on dates/times in mysql, then use the native datetime type so you can take direct advantage of all of mysql's date&time processing functions. If you're going to do most of the processing in your application, a unix timestamp tends to be more portable than a formatted date/time string.
As for the table structure, the simplest way to track edits is a pair of fields (lastedited, and lasteditor). If you want to keep a full list of editors and times, then you'll need a seperate table. If you're keeping track of the changes, then the versioning/trakcing information can go into the same table.

How to delete from a database?

I know of two ways to delete data from a database table
DELETE it forever
Use a flag like isActive/isDeleted
Now the problem with isActive is that I have to track everywhere in my SQL queries that whether the record is active or not. Using DELETE however gets rid of the data forever.
What would be the best way to backup this data?
Assuming I have multiple tables in a database, should I have a common function which just backs everything up and stores it in another table (in XML probably?) or is there any other way.
I am using MySQL but am curious about techniques used in other DBs as well.
Replace the table with a view that hides the inactive items.
Or write a trigger on DELETE that backs up the row to an archive table.
You could use a trigger that fires on deleting records to back them up into some kind of graveyard table.
You could use an isDeleted column and defien a view which selects all columns except isDeleted with the condition isDeleted=false. Then have all your stps work only with the view.
You could maintain a history table, where you back the record up and time stamp
One of the biggest reasons for not deleting data is that it may be required for a relation - for example the the user may decide to delete an old customer from the database, but you still need the customer record because it is referenced by old invoices (which may have a much longer lifespan).
Based on this the best solution is often the "IsDeleted" type of column, combined with a view (Quassnoi has mentioned partitioning, which can help with performance issues that might pop up due to a lot of invisible data).
You can partition your tables on the DELETED column and define the views which would include the condition:
… AND deleted = 0
This will make the queries over the active data just as simple and efficient.
Well, if you were using SqlServer you can use triggers, which will allow you to move the record to a deleted table.