在MySQL中为现有数据生成GUID?

135

我刚刚将一堆数据导入到MySQL表中,我有一个名为“GUID”的列,我想基本上使用新的唯一随机GUID填充所有现有行。

我该如何在MySQL中做到这一点?

我尝试过

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

只需将每个字段都保持相同即可


2
你真的确定它们是一样的吗?我已经尝试过了,大部分字符都是相同的,但在生成的 UUID 中还有一些差异。 - xiaoyifang
是的,我确认,它是相同的! - Cyril N.
2
它对我有效-差异很小,但确实存在。检查的最快方法是向列添加唯一约束。 - PSU
很抱歉在这里帖子又被顶起来了,但是 SET columnID = UUID() 是行得通的 - 只是如果你对大量行做这个操作,UUID 字符的大部分看起来都会是相同的,但细微的差别还是存在的。赞成 PSU 的回答。 - joelc
12个回答

160

我需要在一个已存在的表中添加一个GUID主键列,并将其填充为唯一的GUID,这个带有内部选择的更新查询对我很有效:

UPDATE sri_issued_quiz SET quiz_id=(SELECT uuid());

如此简单 :-)


49
起初我以为这里插入了重复的UUID,因为它们开头和结尾都一样,但实际上它们稍有不同。 - Sam Barnum
7
因为 UUID 是基于 机器和时间戳 生成的。作为一个需要几毫秒运行的查询,它们必须非常非常接近......但永远不会相同......为了确保这一点,一个好的方法是给该列添加一个 UNIQUE 索引。 - balexandre
5
相比于这个答案,被接受的答案似乎有些过头了! - Aritz
8
在MariaDB(10.1.26)中,这似乎不起作用,每个记录都会给出相同的UUID。 - johanvdw
8
这让我每个记录上都生成了相同的UUID,可能是因为它在一个子查询中,MySQL会先执行内部查询并对所有行使用相同的值。要解决这个问题,可以删除子查询:UPDATE sri_issued_quiz SET quiz_id=uuid(); - Chris White
@ChrisWhite,您未完成的编辑还应修改答案中的“内部选择”部分,否则它将与您提出的代码不匹配。 - Joshua Huber

105

我不确定这是否是最简单的方法,但它是有效的。思路是创建一个触发器来完成所有工作,然后执行一个更新表的查询,最后删除这个触发器:

delimiter //
create trigger beforeYourTableUpdate  BEFORE UPDATE on YourTable
FOR EACH ROW
BEGIN
  SET new.guid_column := (SELECT UUID());
END
//

然后执行

UPDATE YourTable set guid_column = (SELECT UUID());

并执行 DROP TRIGGER beforeYourTableUpdate;

更新 另一个不使用触发器的解决方案,但需要主键或唯一索引 :

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

更新

似乎您最初的查询也应该有效(也许您不需要WHERE columnID is not null),因此我的所有花哨的代码都没有必要。


是的,它应该在5.0版本中也能工作。但不要忘记删除触发器! - a1ex07
是的,我在想是否需要在之后检查重复项,还是这将为列中的每一行创建唯一值? - Tom
2
你的原始代码可以正常工作,只需要将columnId=UUID()更改为columnId=(SELECT UUID())。这对我非常有效。所有生成的值非常接近,但每个值都是唯一的。 - EJay
UPDATE db.tablename SET columnID = UUID() 对我有效。 - Marku
1
只是一个提醒,@a1ex07可能会想要添加到答案中:在5.6中(我没有测试其他版本),如果columnId =(SELECT UUID())在存储过程中,所有UUID值将相同。 - Phil
显示剩余4条评论

27

已批准的解决方案确实创建了唯一的ID,但乍一看它们看起来是相同的,只有前几个字符不同。

如果您想要看起来不同的密钥,请尝试这个:

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 |
+------------------------+----------------------------------+

我正在使用MySQL服务器版本:5.5.40-0+wheezy1(Debian)


10
在我的情况下,我需要在生成的GUID中添加连字符。我使用了这个语句: SELECT INSERT(INSERT(INSERT(INSERT(MD5(UUID()), 9, 0, '-'), 14, 0, '-'), 19, 0, '-'), 24, 0, '-') 这个查询语句不太优美,但它完成了工作。 - solo
10
MD5比UUID不够唯一吗?我担心会出现碰撞。 - Adam
@Adam 你说得对。虽然碰撞很少发生,但MD5并不是唯一的。我不建议使用这种方法来获得OP想要的结果。关于此有很好的讨论:链接 - Miky Dal

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

2
完美,完美,完美!!这样的小事情可以产生巨大的影响!! - thekosmix
可以确认,对于我来说设置多行不同UUID的最简单且唯一有效的解决方案。 - rabudde

8

我需要进行一些补充,因为当我尝试修改生成的UUID时,结果变得很奇怪。我发现Rakesh答案是最简单有效的方法,但如果你想去掉破折号,则不适用。

供参考:

UPDATE some_table SET some_field=(SELECT uuid());

这个本身很完美。但是当我尝试这样做时:
UPDATE some_table SET some_field=(REPLACE((SELECT uuid()), '-', ''));

然后所有的结果值都相同(不是微妙的差异 - 我用 GROUP BY some_field 查询进行了四重检查)。无论我如何安排括号,都会发生同样的事情。
UPDATE some_table SET some_field=(REPLACE(SELECT uuid(), '-', ''));

似乎在用REPLACE包围生成UUID的子查询时,它只运行一次UUID查询,这对于比我聪明得多的优化开发人员来说可能是很合理的,但对我来说不是。
为了解决这个问题,我只需将其分成两个查询即可:
UPDATE some_table SET some_field=(SELECT uuid());
UPDATE some_table SET some_field=REPLACE(some_field, '-', '');

显然,这是一个简单的解决方案,但希望这能为某个人节省我刚刚浪费的时间。


谢谢,你确实帮我节省了一些时间。 :) - Klaus

4

我遇到了大致相同的问题。在我的情况下,uuid被存储为BINARY(16)并具有NOT NULL UNIQUE约束。

当相同的UUID为每一行生成时,我遇到了问题,而UNIQUE约束不允许这种情况。所以这个查询无法工作:

UNHEX(REPLACE(uuid(), '-', ''))

但是对我而言,当我使用带有嵌套内部选择的查询时,它有效:

UNHEX(REPLACE((SELECT uuid()), '-', ''))

然后为每个条目产生唯一结果。


4

看起来只是一个简单的错别字。你是不是想说"...where columnId null"?

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

1
当我读到这个问题时,我也有同样的想法,但我不这么认为:听起来他的列包含值,但不是唯一的值。在你回答之前很久就已经给出了答案,已经显示出需要什么。不应该有WHERE子句。生成的值非常相似,因此必须仔细查看它们才能确定它们确实不同。 - ToolmakerSteve

3

MYsql

UPDATE tablename   SET columnName = UUID()

oracle

UPDATE tablename   SET columnName = SYS_GUID();

SQLSERVER

UPDATE tablename   SET columnName = NEWID();;

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

2
请在您的代码中添加一些解释说明其工作原理。没有注释的代码并不总是容易让其他SO用户理解。 - Simas Joneliunas
如果您想在现有数据中更新UUID,请按照上述条件运行查询。 - Ashutosh Niranjan

1
SELECT CONCAT(SUBSTRING(REPLACE(UUID(),'-',''), 1, 5), SUBSTRING(UPPER(REPLACE(UUID(),'-','')), 4, 5), SUBSTRING('@#$%(*&', FLOOR(RAND()*(1-8))+8, 1)) pass

我做了这个:

选择五个小写字母、五个大写字母和一个特殊字符:SELECT


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接