MySQL Timestamp field - mysql

Is it possible to set a field to Timestamp but not have it change on update to current timestamp?
I'm trying to do that using phpMyAdmin and it doesn't let me remove the default on update CURRENT_TIMESTAMP
See this question and answer: Support user time zones
I am trying to use the TIMESTAMP as it will allow me to play around with the timezones easily.
Is it not possible to keep the data in that field intact when updating the same row?

This is the behaviour of TIMESTAMP. It can be confusing alright. Read this to work through it. Alternatively consider using a DATETIME.

The server allows any combination of DEFAULT and ON UPDATE, if phpMyAdmin doesn't let you set it, then it's maybe a bug in phpMyAdmin. Anyway, it's important to note that timestamp columns are treated specially in mysql, so if you have more than one of this type in your table, it's well possible that it's not gonna work the way you expect.
From the mysql docs:
In a CREATE TABLE statement, the first TIMESTAMP column can be declared in any of the following ways:
With both DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP clauses, the column has the current timestamp for its default value, and is automatically updated.
With neither DEFAULT nor ON UPDATE clauses, it is the same as DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
With a DEFAULT CURRENT_TIMESTAMP clause and no ON UPDATE clause, the column has the current timestamp for its default value but is not automatically updated.
With no DEFAULT clause and with an ON UPDATE CURRENT_TIMESTAMP clause, the column has a default of 0 and is automatically updated.

Use the command interface.
Looks like you must specify an "DEFAULT CURRENT_TIMESTAMP" attribute on table creation to get that behaviour.
documentation here.

Related

Create mySQL BEFORE/AFTER UPDATE trigger

Trying to understand how to make a trigger in mysql to automatically set a value in a record field. Not even sure if I need a BEFORE or AFTER trigger.
I have a table with one field named date_created and another date_updated, both of type datetime. The date_created field is set to NOT NULL and default to CURRENT_TIMESTAMP. The date_updated field is currently set to NULL, but I can change that if needed.
Whenever a new record is created, the date_created field gets filled automatically. This way I can omit the field from an input FORM.
Now whenever the record gets updated, I'd like for the date_updated field to be filled-in automatically - for any subsequent updates.
I've tried several versions but keep getting errors.
You don't need a trigger for this case. Use DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
Read this manual page for details: https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html

Timestamp in mysql column

I'm uploading a datababase to MySQL and get this problem:
ERROR 1293 (HY000) at line 31: Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
The problem is that of two columns with "Timestamp" data type in that table, only one should have "Current Timestamp" value, while the other default value is "null". When I upload the database, both columns' value get changed to "Current Timestamp", which makes the process of exporting and importing very annoying, since I have to manually change it back to null before importing again.
Any idea why it automatically changes to "current timestamp"? This is an Amazon EC2 linux instance (see attached mysql version)
Before version 5.6, MySQL makes an assumption when you declare a timestamp column... specifically, it assumes the first timestamp column on a table will be the one that has the automatic update attributes.
If you don't explicitly disable the behavior on the first timestamp, it's implicitly enabled, which causes the explicit automatic value on a later timestamp to be rejected. It isn't enough not to ask.
It need not be the first TIMESTAMP column in a table that is automatically initialized or updated to the current timestamp. However, to specify automatic initialization or updating for a different TIMESTAMP column, you must suppress the automatic properties for the first one. Then, for the other TIMESTAMP column, the rules for the DEFAULT and ON UPDATE clauses are the same as for the first TIMESTAMP column, except that if you omit both clauses, no automatic initialization or updating occurs.
To suppress automatic properties for the first TIMESTAMP column, do either of the following:
Define the column with a DEFAULT clause that specifies a constant default value.
Specify the NULL attribute. This also causes the column to permit NULL values, which means that you cannot assign the current timestamp by setting the column to NULL. Assigning NULL sets the column to NULL.
— https://dev.mysql.com/doc/refman/5.5/en/timestamp-initialization.html
So, for your first timestamp -- if it's not the one you want to be the automatic timestamp -- use either one of these column type declarations (they're identical):
TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00'
TIMESTAMP NOT NULL DEFAULT 0 -- automatically expanded to '0000-00-00 00:00:00'
This should allow you to copy this table definition between systems without issue.
This silliness was fixed in MySQL Server 5.6, where the system variable explicit_defaults_for_timestamp disables the implicit automatic behavior for the first timestamp in a table.
If you start a server running 5.6 without setting this option, a warning is written to the error log.
[Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please
use --explicit_defaults_for_timestamp server option (see documentation
for more details).
The warning is reminding you that you still have the legacy behavior, which is deprecated in 5.6.

How do I remove ON UPDATE CURRENT_TIMESTAMP from an existing column?

I did a dump of a mysql 5.5 database and loaded it into a 5.6 server.
The dump added ON UPDATE CURRENT_TIMESTAMP to a bunch of columns that didn't have it previously.
I'm searching for an ALTER TABLE statement that will remove the ON UPDATE CURRENT_TIMESTAMP rule without making any other changes. In my imagination it should be something like ON UPDATE NOOP or ON UPDATE NO_CURRENT_TIMESTAMP.
ON UPDATE JUST_BE_A_NORMAL_COLUMN?
I tried using the "Clear default" option in mysql workbench and it did the opposite of what it should have done - it gave the column a default!
I was able to get rid of the default with ALTER TABLE t ALTER COLUMN c DROP DEFAULT, so the column is mandatory in INSERTs (just like it was before the dump/reload, as I wanted it) but the unwanted behavior on UPDATEs remains.
I have not enabled the explicit_defaults_for_timestamp option. If I was starting fresh I'd definitely use that option since it seems a lot more sane. But since I already had the columns configured the way I wanted them in 5.5, I expected them to keep the same semantics when transferred to 5.6. Apparently mysqldump just wasn't smart enough.
At this point I'm not sure I understand what effects would result from enabling explicit_defaults_for_timestamp. Would that option change the behavior of existing tables, or does it only change the interpretation of future CREATE TABLE commands? Would turning it on somehow help me fix the broken columns?
UPDATE:
A similar question is here but that one is about creating a new table, not altering an existing column. In fact that question is the one I used as a guide when creating the tables on the 5.5 server. I used the 2-step procedure: create with default 0 to suppress ON UPDATE CURRENT_TIMESTAMP, then drop default.
The 2-step procedure definitely doesn't produce the correct result on the 5.6 server without explicit_defaults_for_timestamp; this is a sign that either 5.6 doesn't perfectly imitate the old behavior in this mode, or the old server never did what I thought it was doing. I can't be sure which.
ALTER TABLE mytable
CHANGE mycolumn
mycolumn TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
I believe this will reset and void the ON UPDATE. This would effectively make this definition:
CREATE TABLE mytable (
# Other Columns
mycolumn timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
)
Change into this one:
CREATE TABLE mytable (
# Other Columns
mycolumn timestamp NOT NULL default CURRENT_TIMESTAMP
)
If you wanted to reset the column entirely, you should be able to simply redefine it like:
ALTER TABLE mytable
CHANGE mycolumn
mycolumn TIMESTAMP NOT NULL;
Using the ideas from the other answers, and a couple of freshly installed mysql server instances, I have done a comparison of the behavior of several different CREATE and ALTER commands on 3 different server configurations:
mysql 5.5.45
mysql 5.6.26 without explicit_defaults_for_timestamp
mysql 5.6.26 with explicit_defaults_for_timestamp
The easiest one to explain is 5.6 with explicit_defaults_for_timestamp. Everything is sane. The timestamp type is not noticeably different from any other type. Columns created before the explicit_defaults_for_timestamp flag was turned on retain their old defaults and magic update.
In 5.5, the implicit defaults happen when a timestamp column is created (if it is the first timestamp column in the table). These are well documented already. The magic update behavior can be avoided by setting an explicit default, and then the default can be removed, leaving the column with the 3 desired attributes: non-nullable, no default, no magic update. This is the result of CREATE TABLE t (TIMESTAMP c NOT NULL DEFAULT 0) and ALTER TABLE t ALTER COLUMN c DROP DEFAULT.
This state can't be recreated with a single CREATE TABLE command, and it doesn't survive a mysqldump.
5.6 without explicit_defaults_for_timestamp is the most interesting case. It's almost the same as 5.5, but the DROP DEFAULT command is different. If you try the "create with default 0 then drop default" sequence, the magic update attribute appears as a side effect of the drop. But if you make the default CURRENT_TIMESTAMP instead of 0, then the DROP DEFAULT works without the side effect. (Must be a bug. I can't imagine any reason it would intentionally behave this way.)
Therefore this pair of commands will have the same result on all of the server configurations I tested:
ALTER TABLE t CHANGE COLUMN c c TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE t ALTER COLUMN c DROP DEFAULT;
The column now has no default and no magic update.
For your use case I think you would be better served with DATETIME, eg:
ALTER TABLE `my_table`
CHANGE `my_col` `my_col` DATETIME NOT NULL DEFAULT NOW();
This will default to NOW() on insert, but remain unaffected on update.
See this question for a good explanation of the difference:
Should I use field 'datetime' or 'timestamp'?
Try enabling the explicit_defaults_for_timestamp system variable and then redefine the columns with:
ALTER TABLE `table` CHANGE COLUMN `col` `col` TIMESTAMP NOT NULL;
If I understand the documentation correctly enabling explicit_defaults_for_timestamp is mandatory to be able to define TIMESTAMP columns declared as NOT NULL and without an explicit DEFAULT.
If you want to remove both the DEFAULT value and ON UPDATE value, nothing but the following helped me
ALTER TABLE `your_table` CHANGE `your_column` `your_column` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00';

MySQL MD5(CURRENT_TIMESTAMP) On Update

I'm creating a user registration form and when I get to confirming the user's email by emailing them, I need some sort of unique string to confirm against.
Instead of generating one in PHP and inserting it into the database, I wanted to try and add a column to my table that would hold a unique value that I could use whenever I needed to confirm something.
What I want to do is set the value to an MD5 of the current timestamp. I tried just doing SELECT MD5(CURRENT_TIMESTAMP) in phpMyAdmin just to see if it would let me and it did so I thought I'd add that to an update condition but it doesn't seem to be letting me.
ALTER TABLE users ADD confirmation VARCHAR(40) DEFAULT NULL ON UPDATE MD5(CURRENT_TIMESTAMP);
The above is what I've tried. I get an error and I don't know how else to do it.
Is there anyway I can do this or something similar? Side question, does the ON UPDATE trigger on a row that just got inserted?
The syntax you are trying to use doesn't exist. It looks like you are thinking of ON UPDATE CURRENT_TIMESTAMP but that is a rather specific command, as per https://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html
Use of DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP is
specific to TIMESTAMP.
So the ON UPDATE clause only works with CURRENT_TIMESTAMP and only on fields of type TIMESTAMP.
If you want to use the MD5 of the current timestamp either set a trigger, or just manually set the value (e.g. UPDATE users SET confirmation=MD5(CURRENT_TIMESTAMP()) WHERE user_id=123).
Bare in mind that the MD5 of the current timestamp is something that could be quite easily guessed / brute forced, so don't rely on it for security.
Use a universal unique identifier for this purpose. It's a 128-bit unique number; it's designed for this kind of thing.
It has a string representation that fits in 36 bytes.
aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
You can generate these things in most programming languages. In MySQL you use the UUID() function to get one. Every time you call UUID(), you're guaranteed to get a new value.
Add a CHAR(36) column to your database, or just use your VARCHAR(40) column.
You can't use data definition language (ALTER TABLE) to declare ON UPDATE except for a native timestamp. You'll need application code to set your UUID values, just like you do for MD5(CURRENT_TIMESTAMP).

the default value must be a constant; why?

in this said
the default value must be a constant; it cannot be a function or an
expression
can you tell me why ? why we must give constant default value?
This is a limitation in MySQL.
You can either use another RDBMS or get around the problem using a trigger.
CREATE TRIGGER yourtable_insert BEFORE INSERT ON `yourtable`
FOR EACH ROW SET NEW.youraddedcolumn = NOW(), NEW.yourupdatedcolumn = NOW();
One reason I can think of is ambiguity. Should the expression be evaluated before storing it as a default or for each INSERT?
Note that there's one non-constant value you can use in a table definition:
stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
This can only be used on a TIMESTAMP column, but it's useful enough.