如何从 MySQL/MariaDB 中的二进制列格式化 uuid 字符串

How to format uuid string from binary column in MySQL/MariaDB

在 MySQL/MariaDB 中,存储 uuid 的最有效方法是在 BINARY(16) 列中。但是,有时您希望将其作为格式化的 uuid 字符串获取。

给定以下 table 结构,我如何以默认格式获取所有 uuid?

CREATE TABLE foo (uuid BINARY(16));

以下将创建我想要的结果:

SELECT
  LOWER(CONCAT(
    SUBSTR(HEX(uuid), 1, 8), '-',
    SUBSTR(HEX(uuid), 9, 4), '-',
    SUBSTR(HEX(uuid), 13, 4), '-',
    SUBSTR(HEX(uuid), 17, 4), '-',
    SUBSTR(HEX(uuid), 21)
  ))
FROM foo;

这是使用 concat_ws

的替代方法

将原始 uuid 存储在变量@x 中

SELECT @x := hex(uuid)
FROM foo;

使用CONCAT_WS和SUBSTR解析人类可读的UUID

SELECT
  LOWER(CONCAT_WS('-',
    SUBSTR(@x, 1, 8),
    SUBSTR(@x, 9, 4),
    SUBSTR(@x, 13, 4),
    SUBSTR(@x, 17, 4),
    SUBSTR(@x, 21)
  )) AS uuid;

MySQL 8 加 two new UUID functions:

所以:

SELECT BIN_TO_UUID(uuid) FROM foo

在早期(8 之前)版本中,您可以在 MySQL 中创建一个 function,如下所示:

CREATE
  FUNCTION uuid_of(uuid BINARY(16))
  RETURNS VARCHAR(36)
  RETURN LOWER(CONCAT(
  SUBSTR(HEX(uuid), 1, 8), '-',
  SUBSTR(HEX(uuid), 9, 4), '-',
  SUBSTR(HEX(uuid), 13, 4), '-',
  SUBSTR(HEX(uuid), 17, 4), '-',
  SUBSTR(HEX(uuid), 21)
));

然后只需在您的查询中使用它:

SELECT
  uuid_of(id)
  name,
  age
FROM users

它产生:

(c6f5703b-fec2-43fd-8f45-45f06583d450, Some name, 20)

正确的结果是由下面的脚本生成的,其他脚本生成了一个 UUID 但不是正确的。

CONCAT(
    substr(hex(Id), 7, 2), substr(hex(Id), 5, 2), substr(hex(Id), 3, 2), substr(hex(Id), 1, 2), '-'
    , substr(hex(Id), 11, 2) , substr(hex(Id), 9, 2) , '-'
    , substr(hex(Id), 15, 2) , substr(hex(Id), 13, 2) , '-'
    , substr(hex(Id), 17, 4) , '-'
    , substr(hex(Id), 21, 12) 
    )

结果 运行 其他脚本生成了错误的 UUID,如下所示:

  • 预期的 UUID - 2e9660c2-1e51-4b9e-9a86-6db1a2770422
  • 生成了什么 - c260962e-511e-9e4b-9a86-6db1a2770422

如您所见,它们是不同的。

如果您正在寻找相反的方法,即如何将字符串转换为二进制,也许要进行连接或其他操作,请参见此处:Convert UUID to/from binary in Node

这篇 SQL 运行 在 Mysql 5.7 上帮助我锁定了概念:

SELECT
  LOWER(CONCAT(
    SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 1, 8), '-',
    SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 9, 4), '-',
    SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 13, 4), '-',
    SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 17, 4), '-',
    SUBSTR(HEX(UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))), 21)
  ))

输出为43d597d7-2323-325a-90fc-21fa5947b9f3

字符串 -> 二进制

所以 UNHEX(REPLACE('43d597d7-2323-325a-90fc-21fa5947b9f3', '-', ''))INSERT / UPDATE / JOIN / SELECT 期间将 UUID 转换为二进制文件,并且

二进制 -> 字符串

LOWER(CONCAT(
  SUBSTR(HEX(uuid), 1, 8), '-',
  SUBSTR(HEX(uuid), 9, 4), '-',
  SUBSTR(HEX(uuid), 13, 4), '-',
  SUBSTR(HEX(uuid), 17, 4), '-',
  SUBSTR(HEX(uuid), 21)
))

根据这张 Jira 票证,https://jira.mariadb.org/browse/MDEV-15854 UUID_TO_BIN 和 BIN_TO_UUID 没有进入 Mariadb 服务器版本 10.5。如果您使用的是 Mariadb 服务器的这个版本和以下版本,您将不得不使用上面提到的自定义实现。