UUID as default for MySQL id column - mysql

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()));

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.

Convert default column value from datetime to varchar

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.

MySQL converting to TINYINT

Under what circumstances will MySQL convert types to TINYINT? I know that a BOOL or BOOLEAN type in mysql DDL will automatically be converted to TINYINT(1) for for true or false. I am analyzing a database which has a type of varchar(16) on a field in one table, and tinyint(4) on the same field on another table? E.g t1.name varchar(15) and t2.name tinyint(4) where t1.name=t2.name.
Don't rely on implicit type conversion, do your datatype analysis manually:
First lets see what MySQL thinks as the best col-type for your data. Run a
SELECT * FROM table PROCEDURE Analyse()
Analyse your data further by saying
SELECT * FROM table WHERE varcharCol NOT REGEXP '^[0-9].*$'
To get all non-numeric values in varcharCol. If there are non you finally have to check value-ranges of different MySQL-types here.
Then you are ready to convert your varcharCol e.g. to TINYINT.

how to auto number ( auto increment ) guid field in mysql database

In sql-server there is function to auto-increment guid fields.
CREATEGUID()
how can I do the same thing in Mysql?
I'm new in database programing.
I want to create primary key field 16byte auto-incremented.
You can create a BEFORE INSERT trigger to check new value for the auto-increment guid field, and if it is NULL, set value = UUID().
This function may be useful too - UUID_SHORT().
UUID_SHORT() - Returns a “short” universal identifier as a 64-bit unsigned integer (rather than a string-form 128-bit identifier as returned by the UUID() function).
MySQL has UUID() function which returns char/varchar. You can use, for example, either BINARY(16) or CHAR(36) to save data like that (binary requires some data translation before insertion).
But MySQL supports AUTO_INCREMENT for numeric datatypes only.