MySQL UUID_SHORT data type - mysql

I have user table. The primary key is user_id which has a datatype bigint(20).
I generate a user_id using UUID_SHORT() via trigger below. The issue is I get a warning when I try to insert a record as follows:
Warning: #1366 Incorrect integer value: '' for column 'user_id' at row 1
My phpMyAdmin trigger is as follows:
BEGIN
SET NEW.user_id=UUID_SHORT();
END
Any reason why I am getting this warning? Have I set the datatype correctly?

INT is a four-byte signed integer, while UUID_SHORT() returns a 64-bit (i.e. 8 byte) unsigned integer. You are trying to store a 64-bit data type into a 4-byte INT and MySQL appears to be storing an empty string '' into the field user_id.
From the MySQL manual:
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).
You should use the BIGINT UNSIGNED type instead.

will not work if you try to insert from PMA, as it generate this kind of query :
INSERT INTO `users` (`user_id`, `name`) VALUES ('', 'sami')
you can replace the '' with NULL, or remove user_id from the insert
INSERT INTO `users` (`name`) VALUES ('sami')
this will solve the warning problem.

Related

MariaDB table with UUID primary key as BINARY(16) NOT NULL

I want to use BINARY UUIDs as my primary key in my tables, but using my own custom functions that generates optimised UUIDs loosely based on this article: https://mariadb.com/kb/en/guiduuid-performance/
The table structure and two main functions of interest here are:
CREATE TABLE `Test` (
`Id` BINARY(16),
`Data` VARCHAR(100)
) ENGINE=InnoDB
ROW_FORMAT=DYNAMIC CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
CREATE DEFINER = 'user'#'%' FUNCTION `OPTIMISE_UUID_STR`(`_uuid` VARCHAR(36))
RETURNS VARCHAR(32) CHARACTER SET utf8mb4
DETERMINISTIC
NO SQL
SQL SECURITY INVOKER
COMMENT ''
BEGIN
/*
FROM
00 10 20 30
123456789012345678901234567890123456
====================================
AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE
TO
00 10 20 30
12345678901234567890123456789012
================================
CCCCBBBBAAAAAAAADDDDEEEEEEEEEEEE
*/
RETURN UCASE(CONCAT(
SUBSTR(_uuid, 15, 4), /* Time nodes reversed */
SUBSTR(_uuid, 10, 4),
SUBSTR(_uuid, 1, 8),
SUBSTR(_uuid, 20, 4), /* MAC nodes last */
SUBSTR(_uuid, 25, 12)));
END;
CREATE DEFINER = 'user'#'%' FUNCTION `CONVERT_OPTIMISED_UUID_STR_TO_BIN`(`_hexstr` BINARY(32))
RETURNS BINARY(16)
DETERMINISTIC
NO SQL
SQL SECURITY INVOKER
COMMENT ''
BEGIN
/*
Convert optimised UUID from string hex representation to binary. If the UUID is not optimised, it makes no sense to convert
*/
RETURN UNHEX(_hexstr);
END;
I cannot use my custom functions in column definition as shown below
CREATE TABLE `Test` (
`Id` BINARY(16) NOT NULL DEFAULT CONVERT_OPTIMISED_UUID_STR_TO_BIN(OPTIMISE_UUID_STR(UUID())),
I get the error "Function or expression 'OPTIMISE_UUID_STR()' cannot be used in the DEFAULT clause of Id"
So I tried using the same in Triggers:
CREATE DEFINER = 'user'#'%' TRIGGER `Test_before_ins_tr1` BEFORE INSERT ON `Test`
FOR EACH ROW
BEGIN
IF (new.Id IS NULL) OR (new.Id = X'0000000000000000') OR (new.Id = X'FFFFFFFFFFFFFFFF') THEN
SET new.Id = CONVERT_OPTIMISED_UUID_STR_TO_BIN(OPTIMISE_UUID_STR(UUID()));
END IF;
END;
The above works pretty good, but the issue is that I cannot define the Id column as PRIMARY KEY, which I want to because PRIMARY KEYs have to be NOT NULL, and setting this means I have to pre-generate optimised UUIDs. I do not want to do this as I would like the DB to take care of generating the optimised UUIDs.
As you might have inferred looking at the above Trigger definition, I tried setting a default value on the Id column, such as:
Id` BINARY(16) NOT NULL DEFAULT X'0000000000000000'
and
Id` BINARY(16) NOT NULL DEFAULT X'FFFFFFFFFFFFFFFF'
and
Id` BINARY(16) NOT NULL DEFAULT '0' /* I tried setting 0, but always seem to revert to '0' */
and this default value would be picked up by the trigger and a correct optimised UUID assigned. But that also does not work as the DB complains "Column 'Id' cannot be null" even though a DEFAULT value has been set.
So my actual question is: Can I generate a custom (optimised UUID) BINARY value for a PRIMARY KEY column?
Short answer: Yes
Long answer:
The PRIMARY KEY can be almost any datatype with whatever values you can create.
TEXT or BLOB are not allowed. Not even TINYTEXT.
VARCHAR (etc) are not allowed beyond some size (depends on version and CHARACTER SET). VARCHAR(191) (or smaller) works in all combinations. The ubiquitous VARCHAR(255) works in many situations.
MySQL 8.0 has builtin functions for converting between binary and string UUIDs. This also provides functions (like yours) for such: UUIDs
Yes, it's doable even without triggers and/or stored functions:
MariaDB from version 10.6:
Use function SYS_GUID() which returns same result as UUID() but without - characters. The result of this function can be directly converted to a 16-byte value with UNHEX() function.
Example:
CREATE TABLE test (a BINARY(16) NOT NULL DEFAULT UNHEX(SYS_GUID()) PRIMARY KEY);
INSERT INTO test VALUES (DEFAULT);
INSERT INTO test VALUES (DEFAULT);
SELECT HEX(a) FROM test;
+----------------------------------+
| HEX(a) |
+----------------------------------+
| 53EE84FB733911EDA238D83BBF89F2E2 |
| 61AC0286733911EDA238D83BBF89F2E2 |
+----------------------------------+
MariaDB from version 10.7 (as mentioned in danielblack's comment):
Use UUID datatype which stores UUID() (and SYS_GUID()) values as 16 byte:
CREATE TABLE test (a UUID not NULL default UUID() PRIMARY KEY);
INSERT INTO test VALUES (DEFAULT);
INSERT INTO test VALUES (DEFAULT);
SELECT a FROM test;
+--------------------------------------+
| a |
+--------------------------------------+
| 6c42e367-733b-11ed-a238-d83bbf89f2e2 |
| 6cbc0418-733b-11ed-a238-d83bbf89f2e2 |
+--------------------------------------+
Addendum: If you are using a version < 10.6 and your requirements match the following limitations, you could also use UUID_SHORT() function, which generates a 64-bit identifier.

Why can I not change mysql int value?

It seems like a bug because when I set the integer value on a column it says it has been changed successfully but nothing happens and the integer value remains blank.
I can't use the database because I get the error that all my integer columns have incorrect integer values, but when I try to change them to int(11) e.g. nothing is happening.
Does anyone know how to fix this?
I can set columns with varchar datatypes to have values and they work fine.
Fatal error: Uncaught mysqli_sql_exception: Incorrect integer value: '' for column 'topic_id' at row 1 in C:\wamp64\www\mycode\upload2.php on line 32
mysqli_sql_exception: Incorrect integer value: '' for column 'topic_id' at row 1 in C:\wamp64\www\mycode\upload2.php on line 32
Code:
ALTER TABLE `topics` CHANGE `topic_id` `topic_id` INT(11) NOT NULL
AUTO_INCREMENT;
// This isn't changing the int value at all!
You have multiple errors in what you are attempting to do.
First, there is the problem that the values in the table are not integers.
Second, you cannot set a column to auto-increment unless it is the primary key.
One option is to drop the primary key and auto-increment idea. Then you can update the values to NULL and change the column to an int:
update topics
set topic_id = null
where topic_id regexp '[^0-9]';
ALTER TABLE `topics` CHANGE `topic_id` `topic_id` INT(11) ;
Here is a db<>fiddle.
If you really want topic_id to be an auto-increment primary key, then I would suggest recreating the table. Something like this:
create table temp_topics as
select *
from topics;
drop table topics; -- be very careful here!
create table topics (
topic_id int auto_increment primary key,
. . . -- the rest of the columns
);
insert into topics (<list of columns here>)
select <list of columns here>
from temp_topics;
if you wanna change a value you have to update that row.
what you are trying to do is wrong , int data type has fixed length (4 bytes), so when you give it a length , it actually doesn't mean anything and its been ignored by the sql engine
see MySql Ref: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
numeric data types are divided into 3 categoies :
Integer Types (Exact Value) - INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT
Fixed-Point Types (Exact Value) - DECIMAL, NUMERIC
Floating-Point Types (Approximate Value) - FLOAT, DOUBLE

MySQL Auto-Inc Bug?

In my MySQL table I've created an ID column which I'm hoping to auto-increment in order for it to be the primary key.
I've created my table:
CREATE TABLE `test` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 50 ) NOT NULL ,
`date_modified` DATETIME NOT NULL ,
UNIQUE (
`name`
)
) TYPE = INNODB;
then Inserted my records:
INSERT INTO `test` ( `id` , `name` , `date_modified` )
VALUES (
NULL , 'TIM', '2011-11-16 12:36:30'
), (
NULL , 'FRED', '2011-11-16 12:36:30'
);
I'm expecting that my ID's for the above are 1 and 2 (respectively). And so far this is true.
However when I do something like this:
insert into test (name) values ('FRED')
on duplicate key update date_modified=now();
then insert a new record, I'm expecting it to be 3, however now I'm shown an ID of 4; skipping the place spot for 3.
Normally this wouldn't be an issue but I'm using millions of records which have thousands of updates every day.. and I don't really want to even have to think about running out of ID's simply because I'm skipping a ton of numbers..
Anyclue to why this is happening?
MySQL version: 5.1.44
Thank you
My guess is that the INSERT itself kicks off the code that generates the next ID number. When the duplicate key is detected, and ON DUPLICATE KEY UPDATE is executed, the ID number is abandoned. (No SQL dbms guarantees that automatic sequences will be without gaps, AFAIK.)
MySQL docs say
In general, you should try to avoid using an ON DUPLICATE KEY UPDATE
clause on tables with multiple unique indexes.
That page also says
If a table contains an AUTO_INCREMENT column and INSERT ... ON
DUPLICATE KEY UPDATE inserts or updates a row, the LAST_INSERT_ID()
function returns the AUTO_INCREMENT value.
which stops far short of describing the internal behavior I guessed at above.
Can't test here; will try later.
Is it possible to change your key to unsigned bigint - 18,446,744,073,709,551,615 is a lot of records - thus delaying the running out of ID's
Found this in mysql manual http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html
Use a large enough integer data type for the AUTO_INCREMENT column to hold the
maximum sequence value you will need. When the column reaches the upper limit of
the data type, the next attempt to generate a sequence number fails. For example,
if you use TINYINT, the maximum permissible sequence number is 127.
For TINYINT UNSIGNED, the maximum is 255.
More reading here http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id it could be inferred that the insert to a transactional table is a rollback so the manual says "LAST_INSERT_ID() is not restored to that before the transaction"
What about for a possible solution to use a table to generate the ID's and then insert into your main table as the PK using LAST_INSERT_ID();
From the manual:
Create a table to hold the sequence counter and initialize it:
mysql> CREATE TABLE sequence (id INT NOT NULL);
mysql> INSERT INTO sequence VALUES (0);
Use the table to generate sequence numbers like this:
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
mysql> SELECT LAST_INSERT_ID();
The UPDATE statement increments the sequence counter and causes the next call to
LAST_INSERT_ID() to return the updated value. The SELECT statement retrieves that
value. The mysql_insert_id() C API function can also be used to get the value.
See Section 20.9.3.37, “mysql_insert_id()”.
It's really a bug how you can see here: http://bugs.mysql.com/bug.php?id=26316
But, apparently, they fixed it on 5.1.47 and it was declared as INNODB plugin problem.
A duplicate, but same problem, you can see here too: http://bugs.mysql.com/bug.php?id=53791 referenced to the first page mentioned here in this answer.

`id` int(10) NOT NULL auto_increment

Some scripts I migrated are doing lots of
INSERT INTO `table` ( `id` , `fld2` , `fld3`) VALUES ( '', 'v2', 'v3')
id is defined as: int(10) NOT NULL auto_increment.
My database/mysql server (5.1.57) throws error:
1366 - Incorrect integer value: '' for column 'id' at row 1
'' was being accepted without syntax error and did auto-increment the integer field to the next number on the original server (5.1.52). Any idea what could be the difference in the mysql server setup? It couldn't be the version difference, both are 5.1.xx?
Since id is auto_increment you should not mention it in your insert query :
INSERT INTO table (fld2 , fld3) VALUES ('v2', 'v3')
And besides you are inserting string in your id thus in case it was not auto_increment you would get the same error anyway.
Looks like the current server's default settings differ from the previous one. Have a look at MySQL's documentation regarding the strict mode settings.

storing the retrieved datas to the database

I have a php form with three text boxes (webmeasurementsuiteId, webmeasurementsId, Id) and the values in the text boxes are retrieved from other tables of the database. Now my task is to submit the retrieved values in this php form named (mapping) to the database. I have created the table with the following syntax:
CREATE TABLE `mapping` (
`webmeasurementsuiteId` INT NOT NULL,
`webmeasurementsId` INT NOT NULL,
`Id` INT NOT NULL,
PRIMARY KEY (Id)
);
But I am getting an sql error as follows:
INSERT INTO mapping(webmeasurementsuiteId,webmeasurementsId,Id) values ('','','7')
ERROR: Incorrect integer value: '' for column 'webmeasurementsuiteId' at row 1
Can anyone correct my error?
all your columns are INT that means numbers while your insert statement is inserting STRINGs (text) remove the ' around the values in the INSERT-statement and it should work
example:
INSERT INTO mapping(webmeasurementsuiteId,webmeasurementsId,Id) values (0,0,7)
So you used '' for webmeasurementsuiteId which indicates it as a string. just leave the integers to 0 without the parantheses to indicate them as an integer. values (0,0,7) should probably do it.
you cannot insert blank in the values field .
try 0 instead of ''
INSERT INTO mapping(webmeasurementsuiteId,webmeasurementsId,Id) values (0,0,'7')
or alter the columns to take the null values