Convert default column value from datetime to varchar - mysql

I have to add a varchar column to a table which defaults to the current timestamp. To do this I somehow need to convert the value from datetime to varchar.
I tried the following
ALTER TABLE `TableName`
CHANGE COLUMN `DocumentID` `DocumentID` VARCHAR(150) NULL DEFAULT CONVERT(NOW(), CHAR);
or
ALTER TABLE `TableName`
CHANGE COLUMN `DocumentID` `DocumentID` VARCHAR(150) NULL DEFAULT CONVERT(CURRENT_TIMESTAMP, CHAR);
I always get an error message, that my syntax is wrong. I am using MariaDB and HeidiSQL. Is there a way to do this?
EDIT: I am basically looking for a MySQL equivalent of the following SQL Server statement:
ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [DF_TableName_DocumentID] DEFAULT (getdate()) FOR [DocumentID]

MariaDB document says
In MariaDB 10.2.1 you can use most functions in DEFAULT. Expressions
should have parentheses around them.
Hence you may check for the version of MariaDB and use the right syntax (parenthesis around expression):
(CONVERT(CURRENT_TIMESTAMP, CHAR))
Update
As an alternative, you may use Trigger to set the function value for the stable releases (< 10.2)

If you use CURRENT_TIMESTAMP as default value, you must use the datatype that the function retrieves, in this case is a timestamp as you can see in the docs.
I don't know the reasons that may lead you to save this as a varchar. I'm not sure but I think that MariaDB doesn't allow to call functions as default values so you can't convert CURRENT_TIMESTAMP as varchar. You have an alternative approach, make an after insert trigger updating the field (you can call CONVERT(CURRENT_TIMESTAMP, VARCHAR) inside a trigger).
Either way, I recomend to stay with timestamp.
I see the field is called "DocumentID", perhaps you want to save a hash value as identifier? You can archieve this with virtual columns. An example.

Related

How to store unix timestamp as int with default and on update?

I have been updating my MySQL tables with the following:
ALTER TABLE logs ADD COLUMN updateTimeStamp timestamp DEFAULT current_timestamp() ON UPDATE current_timestamp;
This stores the timestamp in the format of
2021-12-29 15:21:34
I tried originally to do the alter like so:
ALTER TABLE logs ADD COLUMN updateTimeStamp timestamp DEFAULT unix_timestamp() ON UPDATE unix_timestamp();
so that could store like 12121232, however that results in an error.
Is there anyway I can achieve the default and on update and store the timestamp in the format of 1212112, instead of the human readable datetime?
I know I can do SELECT unix_timestamt(columnname), but ideally I don't want to do that.
If you want to automatically get an integer when you select the column, you need to make it an int (or int unsigned) type. You can set its default with default (unix_timestamp()) (the extra parentheses are needed when not using one of the historically allowed default values). And you will need to add a trigger to set it on update.
But I suggest you not do that; just use a timestamp type. You just make future trouble for yourself by not using the type designed to store timestamps.

MySQL uuid not creating table [duplicate]

I want to do something like this:
create table app_users
(
app_user_id smallint(6) not null auto_increment primary key,
api_key char(36) not null default uuid()
);
However this results in a error, is there a way to call a function for a default value in mysql?
thanks.
No, you can't.
However, you could easily create a trigger to do this, such as:
CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON app_users
FOR EACH ROW
SET new.api_key = uuid();
As of mysql v8.0.13 it is possible to use an expression as a default value for a field:
The default value specified in a DEFAULT clause can be a literal constant or an expression. With one exception, enclose expression default values within parentheses to distinguish them from literal constant default values.
CREATE TABLE t1 (
uuid_field VARCHAR(32) DEFAULT (uuid()),
binary_uuid BINARY(16) DEFAULT (UUID_TO_BIN(UUID()))
);
As already stated you can't.
If you want to simulate this behavior you can use a trigger in this way:
CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON app_users
FOR EACH ROW
IF new.uuid IS NULL
THEN
SET new.uuid = uuid();
END IF;
You still have to update previously existing rows, like this:
UPDATE app_users SET uuid = (SELECT uuid());
Unfortunately no, MySQL 5 requires constants for the default. The issue was discussed in much more detail in the link below. But the only answer is to allow null and add a table trigger.
MySQL only recently accepted UUID as part of their DB package, and it's not as feature rich as we'd like.
http://www.phpbuilder.com/board/showthread.php?t=10349169
I believe you can't:
the default value must be a constant; it cannot be a function or an expression
Note that MySQL's UUID() returns CHAR(36), and storing UUIDs as text (as shown in the other answers) is obviously inefficient. Instead, the column should be BINARY(16), and you can use UUID_TO_BIN() when inserting data and BIN_TO_UUID() when reading it back.
CREATE TABLE app_users
(
app_user_id SMALLINT(6) NOT NULL AUTO_INCREMENT PRIMARY KEY,
api_key BINARY(16)
);
CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON app_users
FOR EACH ROW
IF new.api_key IS NULL
THEN
SET new.api_key = UUID_TO_BIN(UUID());
END IF;
Note that since MySQL doesn't really know this is a UUID, it can be difficult to troubleshoot problems with it stored as binary. This article explains how to create a generated column that will convert the UUID to text as needed without taking up any space or worrying about keeping separate binary and text versions in sync: https://mysqlserverteam.com/storing-uuid-values-in-mysql-tables/
In MariaDB starting from version 10.2.1 you can. See its documentation.
CREATE TABLE test ( uuid BINARY(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-','')) );
INSERT INTO test () VALUES ();
SELECT * FROM test;
I'm not sure if the above answers are for an older version, but I saw somewhere that you can do this using the unhex() function. I tried it and it works. (maria db version 10.2)
You can do
.... column_name binary(16) not null default unhex(replace(uuid(),'-',''))
and it works. To see the uuid just do hex(column_name).
Harrison Fisk's answer was great when it was written, but now it's outdated.
Nowadays you can use an expression as a DEFAULT value. This is supported since MySQL 8.0 and MariaDB 10.2. Note that, if you're going to use non-deterministic functions like NOW() or USER(), you should not use binlog_format=statement.

UUID as default for MySQL id column

I am trying to add a column to an existing table in MySql 8.0.17. The column needs to contain a UUID and I am trying to set it as a default value.
This is the statement I am executing
ALTER TABLE myTable ADD COLUMN UUID varchar(36) NOT NULL DEFAULT (UUID());
However I am getting the following error
Error Code: 1674. Statement is unsafe because it uses a system function that may return a different value on the slave.
I have read from other posts that it is possible to create a Trigger on the table however i would like to find out whether it is possible to set it directly as the default value on the column.
Also, what would be the advantage of using a binary conversion of the UUID over just a simple UUID ?
Eg.
ALTER TABLE myTable ADD COLUMN UUID binary(16) NOT NULL DEFAULT (UUID_TO_BIN(UUID(), true));
Thanks for your help.
assigning UUID() as DEFAULT value won't work, because It does not guarantee that the same value will be generated on your replica. That is why using TRIGGER is good option for new records (insertions).
If your intention is to update current records as well, you can write an update statement
update myTable
set UUID = UUID()
your column is of type binary(16) which means UUID data is implicitly converted to binary. using UUID_TO_BIN is not needed.
EDIT:
CHAR/VARCHAR is the human-readable format. whereas, binary is the compact format.
That means compressing the 32 characters (36 or more with separators) to the 16-bit format or back to the human-readable format.
If you dont mind about reading UUID, best is to use binary format
Change VARCHAR to CHAR, this will let you use 16bit.
Old Method
ALTER TABLE myTable ADD COLUMN UUID varchar(36) NOT NULL DEFAULT (UUID());
New Method
ALTER TABLE myTable ADD COLUMN UUID BINARY(36) NOT NULL DEFAULT (UUID_TO_BIN(UUID()));

Setting a column as timestamp in MySql workbench?

This might be a really elementary question, but I've never created a table with TIMESTAMP() before, and I'm confused on what to put as the parameters. For example, here:
I just randomly put TIMESTAMP(20), but what does the 20 as a parameter signify here? What should be put in here?
I googled the question, but didn't really come up with anything so... Anyway I'm new to sql, so any help would be greatly appreciated, thank you!!
EDIT
As of MySQL 5.6.4, datatype TIMESTAMP(n) specifies n (0 up to 6) decimal digits of precision for fractional seconds.
Before MySQL 5.6, MySQL did not support fractional seconds stored as part of a TIMESTAMP datatype.
Reference: https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
We don't need to specify a length modifier on a TIMESTAMP. We can just specify TIMESTAMP by itself.
But be aware that the first TIMESTAMP column defined in the table is subject to automatic initialization and update. For example:
create table foo (id int, ts timestamp, val varchar(2));
show create table foo;
CREATE TABLE `foo` (
`id` INT(11) DEFAULT NULL,
`ts` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`val` VARCHAR(2) DEFAULT NULL
)
What goes in parens following a datatype depends on what the datatype is, but for some datatypes, it's a length modifier.
For some datatypes, the length modifier affects the maximum length of values that can be stored. For example, VARCHAR(20) allows up to 20 characters to be stored. And DECIMAL(10,6) allows for numeric values with four digits before the decimal point and six after, and effective range of -9999.999999 to 9999.999999.
For other types, the length modifier it doesn't affect the range of values that can be stored. For example, INT(4) and INT(10) are both integer, and both can store the full range of values for allowed for the integer datatype.
What that length modifier does in that case is just informational. It essentially specifies a recommended display width. A client can make use of that to determine how much space to reserve on a row for displaying values from the column. A client doesn't have to do that, but that information is available.
EDIT
A length modifier is no longer accepted for the TIMESTAMP datatype. (If you are running a really old version of MySQL and it's accepted, it will be ignored.)
Thats the precision my friend, if you put for example (2) as a parameter, you will get a date with a precision like: 2015-12-29 00:00:00.00, by the way the maximum value is 6.
This syntax seems to be from old version of MySQL, prior to 4.1. It has been removed completely from 5.5 https://dev.mysql.com/doc/refman/5.0/en/upgrading-from-previous-series.html
So no point in specifying a width here, as it may be ignored. What version are you running?
MySQL 5.7 appears to support this syntax. The argument passed is the precision. TIMESTAMP(3) will allow millisecond precision. 6 is the highest amount of allowed precision.
reference: http://dev.mysql.com/doc/refman/5.7/en/datetime.html
In MySQL workbench 8.0
TIMESTAMP
doesn't work, you need to add wole statement (if u don't want to update timestamp in future)
TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
than u have e.g :
2020-01-08 19:10:05
but if you want that TIMESTAMP could be modify with the record update than you use :
TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

Can I use a function for a default value in MySql?

I want to do something like this:
create table app_users
(
app_user_id smallint(6) not null auto_increment primary key,
api_key char(36) not null default uuid()
);
However this results in a error, is there a way to call a function for a default value in mysql?
thanks.
No, you can't.
However, you could easily create a trigger to do this, such as:
CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON app_users
FOR EACH ROW
SET new.api_key = uuid();
As of mysql v8.0.13 it is possible to use an expression as a default value for a field:
The default value specified in a DEFAULT clause can be a literal constant or an expression. With one exception, enclose expression default values within parentheses to distinguish them from literal constant default values.
CREATE TABLE t1 (
uuid_field VARCHAR(32) DEFAULT (uuid()),
binary_uuid BINARY(16) DEFAULT (UUID_TO_BIN(UUID()))
);
As already stated you can't.
If you want to simulate this behavior you can use a trigger in this way:
CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON app_users
FOR EACH ROW
IF new.uuid IS NULL
THEN
SET new.uuid = uuid();
END IF;
You still have to update previously existing rows, like this:
UPDATE app_users SET uuid = (SELECT uuid());
Unfortunately no, MySQL 5 requires constants for the default. The issue was discussed in much more detail in the link below. But the only answer is to allow null and add a table trigger.
MySQL only recently accepted UUID as part of their DB package, and it's not as feature rich as we'd like.
http://www.phpbuilder.com/board/showthread.php?t=10349169
I believe you can't:
the default value must be a constant; it cannot be a function or an expression
Note that MySQL's UUID() returns CHAR(36), and storing UUIDs as text (as shown in the other answers) is obviously inefficient. Instead, the column should be BINARY(16), and you can use UUID_TO_BIN() when inserting data and BIN_TO_UUID() when reading it back.
CREATE TABLE app_users
(
app_user_id SMALLINT(6) NOT NULL AUTO_INCREMENT PRIMARY KEY,
api_key BINARY(16)
);
CREATE TRIGGER before_insert_app_users
BEFORE INSERT ON app_users
FOR EACH ROW
IF new.api_key IS NULL
THEN
SET new.api_key = UUID_TO_BIN(UUID());
END IF;
Note that since MySQL doesn't really know this is a UUID, it can be difficult to troubleshoot problems with it stored as binary. This article explains how to create a generated column that will convert the UUID to text as needed without taking up any space or worrying about keeping separate binary and text versions in sync: https://mysqlserverteam.com/storing-uuid-values-in-mysql-tables/
In MariaDB starting from version 10.2.1 you can. See its documentation.
CREATE TABLE test ( uuid BINARY(16) PRIMARY KEY DEFAULT unhex(replace(uuid(),'-','')) );
INSERT INTO test () VALUES ();
SELECT * FROM test;
I'm not sure if the above answers are for an older version, but I saw somewhere that you can do this using the unhex() function. I tried it and it works. (maria db version 10.2)
You can do
.... column_name binary(16) not null default unhex(replace(uuid(),'-',''))
and it works. To see the uuid just do hex(column_name).
Harrison Fisk's answer was great when it was written, but now it's outdated.
Nowadays you can use an expression as a DEFAULT value. This is supported since MySQL 8.0 and MariaDB 10.2. Note that, if you're going to use non-deterministic functions like NOW() or USER(), you should not use binlog_format=statement.