Mysql calculate Timediff on UPDATE - mysql

When I add a row to my table I automatically get current time for "created_at" and "updated_at". So whenever I use update query I'm getting the current time for "updated_at" then I manually calculate the time difference between "created_at" and "updated_at" by using SELECT TIME_TO_SEC(timediff(updated_at, created_at)) from abc
command.
Now I wonder is it possible to create a table which can automatically calculates the time difference in seconds and write it in to another column called "timediff" like adding something timediff ON UPDATE TIME_TO_SEC(timediff(updated_at, created_at))
I've tried something like below but it doesn't work.
CREATE TABLE abc (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
pieces INT(6),
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW() ON UPDATE NOW(),
timediff ON UPDATE TIME_TO_SEC(timediff(updated_at, created_at)) -- that's the issue
)
I don't want to mess with triggers or something complex, I'm looking for the most efficient and easy way to sort it out.
Thanks

From the mysql manual ...
A trigger is a named database object that is associated with a table,
and that activates when a particular event occurs for the table. Some
uses for triggers are to perform checks of values to be inserted into
a table or to perform calculations on values involved in an update.
So, a trigger is intended for precisely the situation you describe. Full info

Related

MySQL not executing CURRENT_TIMESTAMP updates as expected

After lots of research and several similar questions asked here, I have reached some conclusions, but as always it is, there are more questions.
This concerns the explicit_defaults_for_timestamp
Assuming the explicit_defaults_for_timestamp is turned off, this will work:
Schema:
CREATE TABLE IF NOT EXISTS `updated_tables` (
`table_name` VARCHAR(50) NOT NULL,
`updated_at` TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
PRIMARY KEY (`table_name`),
UNIQUE INDEX `table_name_UNIQUE` (`table_name` ASC))
ENGINE = InnoDB;
And the query:
INSERT INTO `updated_tables` (`table_name`,`updated_at`) VALUES ('products',NULL) ON DUPLICATE KEY UPDATE `table_name`=VALUES(`table_name`), `updated_at`=VALUES(`updated_at`);
First time the query is sent, the table is populated with 'products' and with the current time stamp.
If I repeat the query, then the field 'updated_at' is updated. Per definition, when I send NULL value, even though it is not allowed, the MySQL will update the column.
All is fine, and works as expected.
Lets assume I turn on the explicit_defaults_for_timestamp
If I user the above query, it will complain the the NULL is not allowed, which complies with the rules.
Question is, how can I have the same functionality with the explicit_defaults_for_timestamp turned on?
There is the solution to introduce additional column (varchar) which holds for example timestamp in miliseconds. And when I update it, then the MySQL updates the updated_at accordingly.
But it looks like an overkill, I might as well update the updated_at manually. I would like to move that responsibility to MySQL level, not doing it programatically.
In short, how can I perform updates on the table_name, and have the updated_at being set properly. The trick here is I have many updates (cache table), but actually never changing the table_name value at all.
Is it possible? Or I must turn off explicit_defaults_for_timestamp?
Is it bad decision to turn it off? Looking at this AWS RDS post seems it is ok, but I am not sure.
Side question:
If I decide to perform updates on my own, what would be the way to construct it?
Currently the MySQL CURRENT_TIMESTAMP(6) has this construct:
2018-07-10 11:32:43.490100
How could I create same construct with Javascript? First thing coming to my mind is to get current Date, and append to it last 6 digits of current timestamp.
You can create a trigger on INSERT and always set the value for updated_at with the CURRENT_TIMESTAMP - the cleanest approach but this may slow down your updates. Programmatically setting the column value would be faster than firing a trigger.
If you are executing your queries from Node.js then you can use new Date().getTime() to get a Unix timestamp in milliseconds and then construct your query like this
UPDATE tbl SET col_1 = val_1, col_2 = val_2, updated_at = FROM_UNIXTIME(js_milliseconds / 1000)
WHERE id = desired_id

MYSQL query disallowing a timestamp column having two values from the same date

For example if a user inserts '2017-03-13 12:16:18.0' into the timestamp column,
the same user should not be allowed to enter another value in this column IF IT'S ON THE SAME DAY i.e 2017-03-13 (in this case). Or ultimately, update the timestamp column with the previously inserted value ('2017-03-13 12:16:18.0') each time the user tries to insert a timestamp date twice ON THE SAME DAY. I hope I've been explicit enough.
Below is a non-functioning query I came up with, but it shows what I would like the query to do ultimately. Thanks for your help and feedbacks.
INSERT INTO hr.entry(id,entry_time)
VALUES (45,
CASE WHEN '13-03-2017'= CAST(SYSDATE() AS date) THEN
(UPDATE hr.entry
SET entry_time =
(SELECT entry_time
FROM hr.entry
WHERE id=45
AND CAST(entry_time AS date)= CAST(SYSDATE() AS date) )
ELSE
SYSDATE());
You could add a DATE column to your table, and add a unique index to that column. Then, when you insert the timestamp into the timestamp column, you could also insert the date from that timestamp into the DATE column. Attempts to insert a timestamp whose date component already exists in that table would cause MySQL to throw an error.
I think you are going to need a trigger, unless you store the timestamp as a string using YYYY-MM-DD HH:MI:SS format. I don't really recommend that.
So, create a trigger that updates a column called timestamp_date. This simply extracts the date part of the timestamp.
With this column, you can define a unique index:
create unique index entry_userid_timestampdate on entry(userid, timestamp_date);
This will then enforce your condition.
If you decide that you want to store the timestamp as a string, you don't need the trigger (although will need to manually set the "timestamp"). Instead, you can use a prefix:
create unique index entry_userid_timestampstr on entry(userid, left(timestamp_date, 10));

Is it possible to copy a timestamp between MSQL tables?

I am creating a table for users that have been banned from my website. I want to move everything over to the new table, including the TIMESTAMP of when the record was created, but the new table will also have a TIMESTAMP for when they got banned.
When I create a row in table foo, I have a TIMESTAMP that registers when that row was created. I would like to transfer that row to another table (bar) that has a different number of columns, and keep the information from the original TIMESTAMP. How can this be done?
I am fairly new to MySQL, so correct me if I have false assumptions, but it seems that the TIMESTAMP field actually creates a TIMESTAMP when the record is created and that the existing TIMESTAMP value would have to be stored as something else like a VARCHAR in the new table. Am I off base?
EDIT: Solved my own question
I originally had not tried anything because I did not know what to try. In the end, it turns out that simply moving the value from one TIMESTAMP column to another TIMESTAMP column does, in fact, work. The only difference between the two columns is that the original TIMESTAMP has a DEFAULT of CURRENT_TIMESTAMP, whereas the new TIMESTAMP has a DEFAULT of NULL.
I used the following code:
INSERT INTO `bar` (`created`)
SELECT `created` FROM `foo` WHERE `user` = '000'

Does MariaDB store a timestamp when a given row is inserted?

I am dealing with a legacy application that is using MariaDB to emulate a queue. One of the key things missing is that the original design doesn't insert the time the messages in the queue were inserted meaning that the order the messages are processed is not guaranteed.
So far the messages appear to be processed in order as we're only using a single MariaDB instance but I would like to add a created_on column to ensure this continues.
My question is that I need to backfill the created_on column and i was wondering if MariaDB stored the time a given row was inserted into the database?
I realise that unless it is in the schema it is unlikely but occasionally databases will have non-standard extensions that capture this sort of thing. Oracle for example has similar functionality to this.
MariaDB does not have a hidden timestamp. If the table has an AUTO_INCREMENT, that might suffice since you are asking for order, not specifically time.
My opinion of queuing via MySQL/MariaDB: "Don't queue it, just do it". The effort of queuing and dequeuing can become a burden, especially in end cases.
Yes you can, if you were to create a field make sure when you create the field you have the following:
create table test_created_on_table(
created_on timestamp default now() on update now()
);
If you already have a field just take off the "CURRENT_TIMESTAMP" flag on the created field. Whenever you create a new record in the table, just use "NOW()" for a value.
Or.
On the contrary, remove the 'ON UPDATE CURRENT_TIMESTAMP' flag and send the NOW() for that field. That way actually makes more sense.
This would track when row is inserted or updated.
There's another way of doing it by db trigger:
Adding a ModifiedTime
Adding a modified timestamp to a table is the most straight forward. All your have to do is create the field of type TIMESTAMP, and by default, MySQL will automatically update the field when the row is modified.
There are a couple of things to be aware of:
While you can have multiple TIMESTAMP fields in a row, only one of
these can be automatically updated with the current time on update.
If your UPDATE query contains a value for your ModifiedTime field,
this value will be used.
So, to add your modified timestamp field to an existing table, all you need is:
ALTER TABLE my_table ADD ModifiedTime TIMESTAMP;
Adding a CreatedTime
Adding a CreateTime value is a little more involved.
On the latest versions of MySQL it is apparently possible to create a DateTime field with a default value of CURRENT_TIMESTAMP. This wasn’t an option for me as I was having to support a somewhat older version, besides, even on the newer versions of MySQL it is not possible to have more than one field using CURRENT_TIMESTAMP, which of course we are in order to get ModifiedTime working.
So, in order to get a created timestamp, firstly we must add a DATETIME field to the table.
ALTER TABLE my_table ADD CreatedTime datetime NOT NULL;
Note, that this must be created as NOT NULL in order for the next part to work (this is because setting NOT NULL forces an automatic all zeros default).
Next, we must create a trigger, which will automatically be fired when we insert a value into our table and set the created timestamp.
DELIMITER //
DROP TRIGGER IF EXISTS my_table_insert_trigger//
CREATE TRIGGER my_table_insert_trigger
BEFORE INSERT ON my_table
FOR EACH ROW
BEGIN
IF NEW.CreatedTime = '0000-00-00 00:00:00' THEN
SET NEW.CreatedTime = NOW();
END IF;
END;//
DELIMITER ;
Now, when you insert a value into the table, this trigger will fire and, if you’ve not provided a CreatedTime field in your insert query, it will be set to the current time stamp.

Is it possible to see date of update of row mysql?

I'd like to see the update date per-row in a table (InnoDB) in mysql.
Is it possible? The only thing I found is the statistics on a table, not row.
SHOW TABLE STATUS
Any suggestions appreciated!
It is not possible, if you want to track the updates or inserts of 'row' in a table, you have to manually create a logic to do so, for example you can use triggers , to maintain the track of all changes and updates of the 'rows' in any other table.
I don't think you can see specific informations like this for a row.
What I usually do is that I create a column creation_date and modification_date in all my tables and then I fill them for each INSERT or UPDATE query with the function NOW()
You can also create your table this way :
CREATE TABLE [name]
[other colmns]
creation_date DATETIME DEFAULT CURRENT_TIMESTAMP
For this, see this topic.