tracking actual changes in rows when updating table - mysql

I have a table which i keep on updating, from the values of other source in my code. The value I update may or may not be same as the value already in the row.
I need some kind of algorithm may be via mysql (db) or otherwise (part of code) so that I later may be able to identify which rows have a changed value.
There is a date modified column which I change. But that will not be a true indicator as it will always be updated. I want a way by which I can determine whether some predefined columns have changed values,
One solution is this: I can do a select query, then compare and update a changed flag in the table. But that seems complex and not for me as I have a table with a lot of records
Another solution might be to save the md5 checksum of the values in a column and while updating compare the previous md5 and current md5 and so on.
I want to know the best solution.

There's a fairly simple way to handle this problem. Let's think of it as managing when a row's timestamp gets updated.
First of all, as I'm sure you know, your table needs a timestamp column with default settings for INSERT and UPDATE. That looks like this if the column is called ts.
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
Second, you can use an UPDATE query like this to change the values in a row.
UPDATE stock
SET val1 = 'newval1',
val2 = 'newval2',
changed_by = 'current_user_id'
WHERE id = 'id_to_change'
AND NOT (val1 == 'newval1' AND val2 == 'newval2')
The AND NOT clause on the WHERE will prevent the update from taking place unless 'newval1' or 'newval2' would actually provide new values. This works because no rows match the WHERE clause in the update.
When the update is prevented from taking place your automatically set ts column will not change. Neither will the changed_by column be set to the present user's user_id. So, you have the time and user of the most recent genuine change.
Also, many host language interfaces to MySQL have a method call to determine how many rows were affected by a recent UPDATE operation. With this technique, you'll get back zero rows when the row is not updated. That might be convenient for your user interface.
Also, this technique uses a single query, so it's safe if more than one user is trying to update the same row at the same time. There's no need to use a transaction to guarantee that.
(Note that tracking the changed_by user is optional, and will only work if your application can provide the current user's actual id.)
This is reasonably efficient as long as the database search for WHERE id = 'id_to_change' works quickly.
It does require reworking your application's UPDATE queries. But so would any other approach to this problem.

Related

Updating one table in MS Access with data from another

In MS Access 2016 I have a table named Master that periodically needs to gets updated with ‘updated’ data from a table named NewData. Each table has the same fields, except Master has one additional field named OTHER_SOURCES (explained further down). They each have an indexed unique id field named EVENT_ID. I’ve built an update query where the tables are joined one-to-one on the EVENT_ID field. In this query I have the fields in Master getting updated to the new values from the same fields in NewData if the TIMESTAMP field value is different. If the TIMESTAMP values haven’t changed, then those records do not get updated. This part is pretty straightforward and works fine.
However, I have end users that may make occasional changes to the values in the SIZE field of Master that need to be preserved and not overwritten with updated values from NEW_DATA. When a user makes a change in SIZE field, he documents the change with information obtained from other sources, which is stored in the extra field I mentioned earlier: OTHER_SOURCES. Here’s what I need to do, and I just can’t figure it out. Whenever a user has made a change to the SIZE field for a record, I need the update query to not override that value in the SIZE field, but still update the values in all the other fields (again, assuming the TIMESTAMP values are different between the two tables). It seems I need to use an IIF statement, but I’m thinking it needs to be done in VBA where I’m a bit of a hack. See screenshots. I greatly appreciate any help you can offer.
enter image description here
enter image description here
You can still proceed with the update, but update it to the same value as its previous value:
SET SIZE= IIF(nz(OTHER_SOURCES,'')<>'', MASTER.Size, NEW_DATA.Size)
This assumes that anything present in the MASTER.OTHER_SOURCES column indicates that the user has changed MASTER.Size. Note that MASTER.Size will never be updated from NEW_DATA.Size until someone (end user) removes MASTER.OTHER_SOURCES.

Best practice for handling positions of rows

What is the best practice for moving rows. So that you might want to change order of items. Now if you make a new column called order_id or something, wouldn't that fail if I delete or select rows.
Another method I guess is to just switch values completely with an primary ID, so just values except the ID are changed. however I do not know what people usually use. There are so many websites that give you the ability to change order of things.how so they do that?
Every SQL statement that returns a visible result set should include an ORDER BY clause so that the results are consistent. The Standard does not guarantee that the order of rows in a particular table will remain constant or consistent, even if obvious changes aren't made to the table.
What you use for your ORDER BY clause depends on the use case. A date value is the usual choice for a comment thread or blog entry ordering. However, if you want the user to be able to customize the order that a result set shows in, then you have to provide a column that represents the position of the row, and adjust the value of that column when the user makes changes to the order they see.
For example, if you decide that the column will contain a sequential number, starting with 1 for the first row, 2 for the second, etc. then you will be ok to delete rows when they need to be deleted without having to do updates. However, if you insert a row, you will need to give the row you insert the sequential number appropriate for it's position, and update all rows below that with their new position. Same goes for if you move a row from somewhere else to a new location; the rows between the new and old locations need to be updated with new postion indexes.

Preventing 2 users from updating the same record simultaneously

I have a table tbl_orders. It has a quantity field quantity.
In some part of my application I need to decrement the quantity by 1.
I already know the id of the record (available from the client side), so I issue an update statement:
UPDATE tbl_orders
SET quantity=quantity-1
WHERE id= 6
The problem is that this query can accidentally be run multiple times concurrently.
For example, 2 customer service operators may update the same record simultaneously.
That means that the quantity will be decremented by 2 when it is supposed to be decremented once only.
I tried putting the update in a transaction, but that resulted in only delaying the second transaction until the first one was committed. Once it was committed the second update ran and decremented the record again.
How can I make sure that other queries fail if one is modifying a record?
UPDATE:
for an update to be valid the quantity on the client side was the same in the database. For example if a user sees a quantity 5 on his browser and wants to decrement it, the value in database must be the same.
UPDATE 2
I found a good explanation here for optimistic locking using Doctrine 2:
One approach I've used/seen in the past was having a timestamp column. When querying, ensure you have both the ID and the original timestamp at the start of editing the record. Then, when you are trying to update, send via
update YourTable
set counter = counter -1,
TheTimestampColumn = new timestamp value
where ID = yourID
and TheTimeStampColumn = timeStampEditStartedWith
This way, whoever gets to it first with the original starting timestamp would win. For the one following, you would have to track how many records were updated, and if that count equals zero, then you would notify the user that another person made a change to the record while you were viewing it. Do you want to reload the latest data? (or something like that).

Select only recent updated rows in MySQL db with a large data volume

I'm working with a InnoDB table that contains up to 30000 records. Rows are updated frequenty with stock_quantity value. What i need to do is to select only the most recent updated rows with a scheduled task and perform some actions thru a WebService.
Just trying to understand which is the best way for doing this without kill performance. I'm thinking at 3 different solution:
using a datetime column and update its value on each modify. Then select rows where date_col > NOW()-20 min. (20 min. is the frequency crontab is running)
using a boolean column and set the value to true each time the row is modified. Then select rows where boolean_col is true. If the task is executed set back the value of boolean_col to false.
using a second table to store recent updated columns. On each update of a row in table_1 copy the row to table_2. Then select all rows from table_2, perform actions and truncate table_2.
Anyway I'm pretty sure the right solution is not listed up there... so does anyone have some good advice? Thanks.
fist at all,
30,000 record is not that big ...
i prefer method 1 with some additional changes
set the datetime column default to on update current_timestamp
build an index of this column
method 2 will incurred redundant write, and read
method 3 is the worse, it almost double x double the write and read operations
I would personally use your option 2.
I would seriously look at a tigger to set the value to 1 if the row is edited. Of course excluding and update that only effect the boolean col.
I would then have the cron search the table when boolean = 1, return the list process the file and update the field back to 0 once complete.
This would be my approach, but like you said there might be a better way.
Another Idea: You might also want to look at replacing your cron with the tigger and preform the action your cron does on record update might work...

Detect time of last change on a Microsoft Access database table

Does anyone know of a way to detect when the last time a Microsoft Access table has been changed (inserted into or updated)? We used OLEDB via ADO COM to communicate with an access database programmatically and were looking for a way of detecting changes to specific tables. We don't need to know what those changes are, just that changes were made.
The only way to detect if data in the table has changed is to perform a query against the table.
You must add a column of type DATETIME to the table e.g. named LastUpdatedDate that indicates the last updated date/time of each row. Make it NOT NULL so that you will have to write an updated DATETIME value to that column for each INSERT or UPDATE. Also, set the column to have a default of DATE() for the current date stamp or NOW() for the current date/time stamp. Then add a Validation Rule or CHECK constraint e.g. CHECK (LastUpdatedDate = NOW()) to ensure the column is actually updated on each UPDATE and INSERT.
Finally, run a MAX(LastUpdatedDate) query and you will get what you need.
There isn't a way without "manually" writing to a column each time you access the table.
As others have indicated there is no way to track changes without coding it yourself.
There's a simple example at
ACC2000: How to Create an Audit Trail of Record Changes in a Form
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q197592
Audit Trail - Log changes at the record level at:
http://allenbrowne.com/AppAudit.html
The article addresses edits, inserts, and deletes for a form and subform.
Modules: Maintain a history of changes
http://www.mvps.org/access/modules/mdl0021.htm
The History Table routine is designed to write history records that track the changes made to fields in one or more tables.
You will need to implement a timestamp column in your table, and update the value during your data changes.