Generate GUID in MySQL for existing Data? - mysql

I've just imported a bunch of data to a MySQL table and I have a column "GUID" that I want to basically fill down all existing rows with new and unique random GUID's.
How do I do this in MySQL ?
I tried
UPDATE db.tablename
SET columnID = UUID()
where columnID is not null
And just get every field the same

I had a need to add a guid primary key column in an existing table and populate it with unique GUID's and this update query with inner select worked for me:
UPDATE sri_issued_quiz SET quiz_id=(SELECT uuid());
So simple :-)

I'm not sure if it's the easiest way, but it works. The idea is to create a trigger that does all work for you, then, to execute a query that updates your table, and finally to drop this trigger:
delimiter //
create trigger beforeYourTableUpdate BEFORE UPDATE on YourTable
FOR EACH ROW
BEGIN
SET new.guid_column := (SELECT UUID());
END
//
Then execute
UPDATE YourTable set guid_column = (SELECT UUID());
And DROP TRIGGER beforeYourTableUpdate;
UPDATE
Another solution that doesn't use triggers, but requires primary key or unique index :
UPDATE YourTable,
INNER JOIN (SELECT unique_col, UUID() as new_id FROM YourTable) new_data
ON (new_data.unique_col = YourTable.unique_col)
SET guid_column = new_data.new_id
UPDATE once again:
It seems that your original query should also work (maybe you don't need WHERE columnID is not null, so all my fancy code is not needed.

The approved solution does create unique IDs but on first glance they look identical, only the first few characters differ.
If you want visibly different keys, try this:
update CityPopCountry set id = (select md5(UUID()));
MySQL [imran#lenovo] {world}> select city, id from CityPopCountry limit 10;
+------------------------+----------------------------------+
| city | id |
+------------------------+----------------------------------+
| A Coruña (La Coruña) | c9f294a986a1a14f0fe68467769feec7 |
| Aachen | d6172223a472bdc5f25871427ba64e46 |
| Aalborg | 8d11bc300f203eb9cb7da7cb9204aa8f |
| Aba | 98aeeec8aa81a4064113764864114a99 |
| Abadan | 7aafe6bfe44b338f99021cbd24096302 |
| Abaetetuba | 9dd331c21b983c3a68d00ef6e5852bb5 |
| Abakan | e2206290ce91574bc26d0443ef50fc05 |
| Abbotsford | 50ca17be25d1d5c2ac6760e179b7fd15 |
| Abeokuta | ab026fa6238e2ab7ee0d76a1351f116f |
| Aberdeen | d85eef763393862e5fe318ca652eb16d |
+------------------------+----------------------------------+
I'm using MySQL Server version: 5.5.40-0+wheezy1 (Debian)

select #i:=uuid();
update some_table set guid = (#i:=uuid());

Just a minor addition to make as I ended up with a weird result when trying to modify the UUIDs as they were generated. I found the answer by Rakesh to be the simplest that worked well, except in cases where you want to strip the dashes.
For reference:
UPDATE some_table SET some_field=(SELECT uuid());
This worked perfectly on its own. But when I tried this:
UPDATE some_table SET some_field=(REPLACE((SELECT uuid()), '-', ''));
Then all the resulting values were the same (not subtly different - I quadruple checked with a GROUP BY some_field query). Doesn't matter how I situated the parentheses, the same thing happens.
UPDATE some_table SET some_field=(REPLACE(SELECT uuid(), '-', ''));
It seems when surrounding the subquery to generate a UUID with REPLACE, it only runs the UUID query once, which probably makes perfect sense as an optimization to much smarter developers than I, but it didn't to me.
To resolve this, I just split it into two queries:
UPDATE some_table SET some_field=(SELECT uuid());
UPDATE some_table SET some_field=REPLACE(some_field, '-', '');
Simple solution, obviously, but hopefully this will save someone the time that I just lost.

Looks like a simple typo. Didn't you mean "...where columnId is null"?
UPDATE db.tablename
SET columnID = UUID()
where columnID is null

I faced mostly the same issue.
Im my case uuid is stored as BINARY(16) and has NOT NULL UNIQUE constraints.
And i faced with the issue when the same UUID was generated for every row, and UNIQUE constraint does not allow this. So this query does not work:
UNHEX(REPLACE(uuid(), '-', ''))
But for me it worked, when i used such a query with nested inner select:
UNHEX(REPLACE((SELECT uuid()), '-', ''))
Then is produced unique result for every entry.

MYsql
UPDATE tablename SET columnName = UUID()
oracle
UPDATE tablename SET columnName = SYS_GUID();
SQLSERVER
UPDATE tablename SET columnName = NEWID();;

UPDATE db.tablename SET columnID = (SELECT UUID()) where columnID is not null

// UID Format: 30B9BE365FF011EA8F4C125FC56F0F50
UPDATE `events` SET `evt_uid` = (SELECT UPPER(REPLACE(#i:=UUID(),'-','')));
// UID Format: c915ec5a-5ff0-11ea-8f4c-125fc56f0f50
UPDATE `events` SET `evt_uid` = (SELECT UUID());
// UID Format: C915EC5A-5FF0-11EA-8F4C-125FC56F0F50
UPDATE `events` SET `evt_uid` = (SELECT UPPER(#i:=UUID()));

I got this error when using mysql as sql_mode = "". After some testing, I decided that the problem was caused by this usage. When I tested on the default settings, I found that this problem was not there.
Note: Don't forget to refresh your connection after changing the mode.

SELECT CONCAT(SUBSTRING(REPLACE(UUID(),'-',''), 1, 5), SUBSTRING(UPPER(REPLACE(UUID(),'-','')), 4, 5), SUBSTRING('##$%(*&', FLOOR(RAND()*(1-8))+8, 1)) pass
I did this SELECT, five character lower case, five character upper case and one special character.

Related

MySQL 8 - Trigger on INSERT - duplicate AUTO_INCREMENT id for VCS

Trying to
create trigger that is called on INSERT & sets originId = id (AUTO_INCREMENT),
I've used SQL suggested here in 1st block:
CREATE TRIGGER insert_example
BEFORE INSERT ON notes
FOR EACH ROW
SET NEW.originId = (
SELECT AUTO_INCREMENT
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'notes'
);
Due to information_schema caching I have also set
information_schema_stats_expiry = 0
in my.cnf file. Now information gets updated almost instantly on every INSERT, as I've noticed..
But, performing "direct" INSERTs via console with ~2min intervals, I keep getting not updated AUTO_INCREMENT values in originId.
(They shoud be equal to id fields)
While explicit queries, fetching AUTO_) result in updated correct values.
Thus I suspect that the result of SELECT AUTO_INCREMENT... subquery gets somehow.. what? cached?
How can one get around this?
Thank you.
Edit 1
I intended to implement sort of VCS this way:
User creates new Note, app marks it as 'new' and performs an INSERT in MySQL table. It is the "origin" note.
Then user might edit this Note (completely) in UI, app will mark is as 'update' and INSERT it in MySQL table as a new row, again. But this time originId should be filled with an id of "origin" Note (by app logics). And so on.
This allows PARTITIONing by originId on SELECT, fetching only latest versions to UI.
initial Problem:
If originId of "origin" Note is NULL, MySQL 8 window function(s) in default (and only?) RESPECT_NULL mode perform(s) framing not as expected ("well, duh, it's all about your NULLs in grouping-by column").
supposed Solution:
Set originId of "origin" Notes to id on their initial and only INSERT, expecting 2 benefits:
Easily fetch "origin" Notes via originId = id,
perform correct PARTITION by originId.
resulting Problem:
id is AUTO_INCREMENT, so there's no way (known to me) of getting its new value (for the new row) on INSERT via backend (namely, PHP).
supposed Solution:
So, I was hoping to find some MySQL mechanism to solve this (avoiding manipulations with id field) and TRIGGERs seemed a right way...
Edit 2
I believed automated duplicating id AUTO_INCREMENT field (or any field) within MySQL to be extra fast & super easy, but it totally doesn't appear so now..
So, possibly, better way is to have vcsGroupId UNSIGNED INT field, responsible for "relating" Note's versions:
On create and "origin" INSERT - fill it with MAX(vcsGroupId) + 1,
On edit and "version" INSERT - fill it with "sibling"/"origin" vcsGroupId value (fetched with CTE),
On view and "normal" SELECT - perform framing with Window Function by PARTITION BY vcsGroupId, ORDER BY id or timestamp DESC, then just using 1st (or ascending order by & using last) row,
On view and "origin" SELECT - almost the same, but reversed..
It seems easier, doesn't it?
What you are doing is playing with fire. I don't know exactly what can go wrong with your trigger (beside that it doesn't work for you already), but I have a strong feeling that many things can and will go wrong. For example: What if you insert multiple rows in a single statement? I don't think, that the engine will update the information_schema for each row. And it's going to be even worse if you run an INSERT ... SELECT statement. So using the information_schema for this task is a very bad idea.
However - The first question is: Why do you need it at all? If you need to save the "origin ID", then you probably plan to update the id column. That is already a bad idea. And assuming you will find a way to solve your problem - What guarantees you, that the originId will not be changed outside the trigger?
However - the alternative is to keep the originId column blank on insert, and update it in an UPDATE trigger instead.
Assuming this is your table:
create table vcs_test(
id int auto_increment,
origin_id int null default null,
primary key (id)
);
Use the UPDATE trigger to save the origin ID, when it is changed for the first time:
delimiter //
create trigger vcs_test_before_update before update on vcs_test for each row begin
if new.id <> old.id then
set new.origin_id = coalesce(old.origin_id, old.id);
end if;
end;
delimiter //
Your SELECT query would then be something like this:
select *, coalesce(origin_id, id) as origin_id from vcs_test;
See demo on db-fiddle
You can even save the full id history with the following schema:
create table vcs_test(
id int auto_increment,
id_history text null default null,
primary key (id)
);
delimiter //
create trigger vcs_test_before_update before update on vcs_test for each row begin
if new.id <> old.id then
set new.id_history = concat_ws(',', old.id_history, old.id);
end if;
end;
delimiter //
The following test
insert into vcs_test (id) values (null), (null), (null);
update vcs_test set id = 5 where id = 2;
update vcs_test set id = 4 where id = 5;
select *, concat_ws(',', id_history, id) as full_id_history
from vcs_test;
will return
| id | id_history | full_id_history |
| --- | ---------- | --------------- |
| 1 | | 1 |
| 3 | | 3 |
| 4 | 2,5 | 2,5,4 |
View on DB Fiddle

MySQL create an integer column that auto-updates to increment value

I'm wondering if I can do this without a trigger:
I want to have an INT column which is auto-updated to increment the integer value.
This is similar but not the same as ON UPDATE CURRENT_TIMESTAMP on a TIMESTAMP or DATETIME column.
I read in the docs it's not possible with ON UPDATE because I can only use literal values unless the column is a TIMESTAMP.
MySQL default and on update
MySQL timestamp initialization
Can I do something else instead of a trigger?
[UPDATE 1]
This example is what I'm trying to achieve:
CREATE TABLE myTable (
stuff VARCHAR (100),
special_col INT DEFAULT 123456789
);
INSERT INTO myTable (stuff) VALUES ('something or other');
SELECT * FROM myTable;
stuff | special_col
----------------------------------------------------
something or other | 123456789
UPDATE myTable SET stuff = 'new info';
SELECT * FROM myTable;
stuff | special_col
----------------------------------------------------
new info | 123456790
The value that the column increments by doesn't have to be 1. It just has to be higher than before.
[UPDATE 2]
I thought there might be some cool mySQL syntax I could use - it does so much non-ANSI SQL, I figured there might be a custom way of doing it.
Anyway, I have given up and I'm implementing a trigger:
CREATE TRIGGER trg_data_update BEFORE UPDATE ON myTable
FOR EACH ROW SET NEW.special_col = OLD.special_col + 1;
Add one to the special_col in the UPDATE as per docs
UPDATE myTable SET stuff = 'new info', special_col=special_col+1;

Mysql Combining the values of multiple columns

I have searched for the answer to this and cannot find it anywhere. Not quite how I want anyway.
I have five Mysql columns in a table, that I want to combine to make one column.
column1value | column2value | column3value | column4value | column5value
Needs to become
column1valuecolumn2valuecolumn3valuecolumn4valuecolumn5value
In one column (Column 1). And I need this to happen for every row.
Many thanks in advance.
If you just want to retrieve the data combined in that fashion:
SELECT CONCAT(
column1value,
column2value,
column3value,
column4value,
column5value
) column1value
FROM my_table
If you want to permanently update the data in the table:
UPDATE my_table
SET column1value = CONCAT(
column1value,
column2value,
column3value,
column4value,
column5value
)
If you furthermore want to remove the old columns:
ALTER my_table
DROP column2value,
DROP column3value,
DROP column4value,
DROP column5value
you can do it like that
select concat(column1value,column2value,column3value,column4value,column5value)
AS allvalues from table1
little demo here
to be all in column 1
UPDATE my_table
SET column1 = CONCAT(column1value,column2value,column3value,column4value,column5value
)

Copy values from one column to another in the same table

How can I make a copy values from one column to another?
I have:
Database name: list
-------------------
number | test
-------------------
123456 | somedata
123486 | somedata1
232344 | 34
I want to have:
Database name: list
----------------
number | test
----------------
123456 | 123456
123486 | 123486
232344 | 232344
What MySQL query should I have?
Short answer for the code in question is:
UPDATE `table` SET test=number
Here table is the table name and it's surrounded by grave accent (aka back-ticks `) as this is MySQL convention to escape keywords (and TABLE is a keyword in that case).
BEWARE!
This is pretty dangerous query which will wipe everything in column test in every row of your table replacing it by the number (regardless of it's value)
It is more common to use WHERE clause to limit your query to only specific set of rows:
UPDATE `products` SET `in_stock` = true WHERE `supplier_id` = 10
UPDATE `table_name` SET `test` = `number`
You can also do any mathematical changes in the process or use MySQL functions to modify the values.
try this:
update `list`
set `test` = `number`
BEWARE : Order of update columns is critical
GOOD: What I want saves existing Value of Status to PrevStatus
UPDATE Collections SET PrevStatus=Status, Status=44 WHERE ID=1487496;
BAD: Status & PrevStatus both end up as 44
UPDATE Collections SET Status=44, PrevStatus=Status WHERE ID=1487496;
try following:
UPDATE `list` SET `test` = `number`
If list is table name and test and number are columns
it creates copy of all values from "number" and paste it to "test"
Following worked for me..
Ensure you are not using Safe-mode in your query editor application. If you are, disable it!
Then run following sql command
for a table say, 'test_update_cmd', source value column col2, target
value column col1 and condition column col3: -
UPDATE test_update_cmd SET col1=col2 WHERE col3='value';
Good Luck!
IF Anyone wants to put Condition
UPDATE bohf SET Sq=IDNo WHERE Table = 'AOF' AND FormSq BETWEEN 13 AND 17
update `table`
set `firstcolumn` = `secondcolumn`

INSERT ... ON DUPLICATE KEY UPDATE with WHERE?

I'm doing a INSERT ... ON DUPLICATE KEY UPDATE but I need the update part to be conditional, only doing the update if some extra condition has changed.
However, WHERE is not allowed on this UPDATE. Is there any workaround for this?
I can't do combinations of INSERT/UPDATE/SELECT since this needs to work over a replication.
I suggest you to use IF() to do that.
Refer: conditional-duplicate-key-updates-with-mysql
INSERT INTO daily_events (created_on, last_event_id, last_event_created_at)
VALUES ('2010-01-19', 23, '2010-01-19 10:23:11')
ON DUPLICATE KEY UPDATE
last_event_id = IF(last_event_created_at < VALUES(last_event_created_at), VALUES(last_event_id), last_event_id);
This is our final solution, works like a charm!
The insert ignore will make sure that the row exists on both the master and slave, in case they've ever diverted.
The update ... where makes sure that only the most recent update, globally, is the end result after all replication is done.
mysql> desc test;
+-------+--------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+-------------------+-------+
| id | int(11) | NO | PRI | NULL | |
| value | varchar(255) | YES | | NULL | |
| ts | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+--------------+------+-----+-------------------+-------+
mysql> insert ignore into test values (4, "foo", now());
mysql> update test set value = "foo", ts = now() where id = 4 and ts <= now();
you could use two insert statements .. since you CAN add a where clause to the select part for the source data.
select two sets of data, one that you will insert with 'on duplicate' and the other will be inserted without 'on duplicate'.
Overview
AWUpsertCondy wants to change BEFORE into AFTER
Problem
AWUpsertCondy does not want the insert query to fail if MySQL detects duplicate primary key
MySQL does not support conditional WHERE clause with ON DUPLICATE KEY UPDATE
Solution
MySQL supports conditional clause with the IF() function
Here we have a simple conditional to update only those items with userid less-than 9
INSERT INTO zzdemo_table02
(lname,userid)
SELECT
lname,userid
FROM(
SELECT
lname,userid
FROM
zzdemo_table01
) as tt01
ON DUPLICATE KEY UPDATE
userid=IF(#doupdate:=IF( (tt01.userid < 9) , True, False),
tt01.userid, zzdemo_table02.userid)
,lname=IF(#doupdate, tt01.lname , zzdemo_table02.lname )
;
Pitfalls
We introduce a MySQL variable #doupdate in order to flag whether or not the UPDATE row meets the condition. Then we use that same variable for all the database columns we use in the UPDATE statement
In the first conditional we both declare the variable and determine whether the conditional applies. This approach is arguably more cumbersome than a WHERE clause
See also
MySQL copy column withtout conditional
table php_lock: name:idString, locked:bool,
time:timestamp, locked_by:string values to insert or
update 1, CURRENT_TIMESTAMP, 'script' where name='wwww' AND
locked=2
INSERT INTO `php_lock` (`name`, locked, `time`, `locked_by`)
(SELECT * FROM
(SELECT `name`,1,CURRENT_TIMESTAMP, 'script' FROM `php_lock`
WHERE `name`='wwww' AND `locked`=2
UNION (
SELECT 'wwww',1 ,CURRENT_TIMESTAMP, 'script')
) AS temp LIMIT 1)
ON DUPLICATE KEY UPDATE locked=VALUES(locked), `time`=VALUES(`time`), `locked_by`=VALUES(`locked_by`);
On duplicate key do not allow us to use where clause, so there are two alternative to achieve the same.
If you know most of the time you will get the duplicate key then
a. Update the table first using update query and where clause
b. If update fails then insert the record into table using insert query
If you know most of the time you are going to insert into table then
a. Insert the record into table using insert ignore query - what it does is actually ignore the insert if duplicate key found
b. If insert ignore fails then update the record using update query
For reference of insert ignore click here