MySql 查询以连接表之间不同存储的 uuid

MySql query to join uuid that's stored differently between tables

我有一个 uuid 作为人类可读的 guid 存储在一个 table 中,但在另一个 table 中它被分成高位和低位。如何编写查询以加入 uuid 上的 tables?

编辑: table2 给定的高位和低位只会有 1 个结果,所以希望效率不会太差,但请考虑这一点进入答案。

table1.uuid = 'b33ac8a9-ae45-4120-bb6e-7537e271808e'
table2.upper_bits = -5531888561172430560, table2.lower_bits = -4940882858296115058

我需要检索 table2.statustable1.* where table2.upper_bits + table2.lower_bits = table1.uuid (伪 where 语句)但我不知道如何求和 table2 upper & 连接的较低值,或如何将 table1 的 uuid 转换为连接的位。

谢谢!

类似这样的方法可能有用...但显然效率很低。

SELECT ...
FROM table1 AS t1 
INNER JOIN table2 AS t2 ON REPLACE(t1.uuid, '-', '') 
                         = CONCAT(HEX(t2.upper_bits), HEX(t2.lower_bits))
...

...您可能会根据 collation/comparison.

强制 upper/lower 大小写

我倾向于 "absolutely necessary" 更改您的数据库结构(以回应您对另一个答案的评论)。为了尽量减少对现有查询和逻辑的影响,您可以更改其中一个 table 以具有与另一个匹配的其他字段,并将触发器添加到 table 以自动 populate/update 新的字段;然后进行一次性更新以设置所有旧记录的值。

我会尝试先修改 t1,因为两个整数上的索引可能 "better" 而不是一个字符串上的索引;但我不确定将字符串转换为高位和低位的方式有多直接。

修改 t2 会更容易,触发器会比 SET NEW.uuid = CONCAT(HEX(NEW.upper_bits), HEX(NEW.lower_bits)); 多一点...我说 "little more than" 因为触发器最好也插入- 也在预期点,因此连接条件可以消除所有函数使用。


编辑:我找到了一种计算纯 SQL:

中的位的方法
SELECT @uuid := REPLACE('b33ac8a9-ae45-4120-bb6e-7537e271808e', '-', '') AS uuid
   , -1 * CAST((~CAST(CONV(SUBSTRING(@uuid, 1, 16), 16, 10) AS SIGNED) + 1) AS SIGNED) AS upper_bits
   , -1 * CAST((~CAST(CONV(SUBSTRING(@uuid, 17, 16), 16, 10) AS SIGNED) + 1) AS SIGNED) AS lower_bits
;

您可以在 t1 的触发器中使用类似的东西,并为新字段一次性更新 t1。

...它甚至可能有助于加入:

ON -1 * CAST((~CAST(CONV(SUBSTRING(REPLACE(t1.uuid, '-', ''), 1, 16), 16, 10) AS SIGNED) + 1) AS SIGNED) 
  = t2.upper_bits
AND -1 * CAST((~CAST(CONV(SUBSTRING(REPLACE(t1.uuid, '-', ''), 17, 16), 16, 10) AS SIGNED) + 1) AS SIGNED) 
  = t2.lower_bits

注意:是的,这两个中的过度转换似乎是必要的(至少在旧版本的 MySQL 我测试了计算。)

最简单的方法是将 lower_bits 和 upper_bits 与 uuid 一起存储在 table1 中。然后在 lower_bits 和 upper_bits 上加入 table。

编辑:如果您只需要一行,并且您确定在其他 table 中会有一个匹配行,则计算uuid= @uuid, lower_bits =@lbits & upper_bits= @ubits, 然后运行 如下:

Select t1.*, t2.status  
From  
(select * from table1 where uuid = @uuid)  as t1
Cross join  
(select status from table2 where lower_bits =@lbits and upper_bits= @ubits) as t2;

这是@Uueerdo 解决方案的一个变体,应该更有效(有点像装饰-加入-取消装饰),但我还运行 无法确定解释:

SELECT t1.*, t2.status
FROM (
  SELECT UUID_TO_BIN(uuid) AS tmpid, *
  FROM table1
) AS t1 INNER JOIN (
  SELECT UUID_TO_BIN(CONCAT(HEX(upper_bits), HEX(lower_bits))) AS tmpid, status
  FROM table2
) AS t2 ON t1.tmpid = t2.tmpid

它可能会使用更多的内存,如果表格有很多行,请记住这一点and/or如果 table1 非常宽。

如果您只需要来自 table1 和 table2 的记录与单个 UUID 匹配,您应该只执行两个查询,而不是连接:

SELECT *
FROM table1
WHERE UUID_TO_BIN(uuid) = UUID_TO_BIN(?)

SELECT status
FROM table2
WHERE UUID_TO_BIN(CONCAT(HEX(upper_bits), HEX(lower_bits))) = UUID_TO_BIN(?)

如果 upper_bitslower_bits 被索引,这将是查询表 2 的更好方法:

SET @tmpid = UUID_TO_BIN(?);

SELECT status
FROM table2
WHERE upper_bits = @tmpid >> 64, lower_bits = _binary X'FFFFFFFFFFFFFFFF' & @tmpid

您可以将类似的逻辑应用于我的第一个解决方案(我认为):

SELECT t1.*, t2.status
FROM (
  SELECT 
    UUID_TO_BIN(uuid) >> 64 AS upper_bits,
    _binary X'FFFFFFFFFFFFFFFF' & UUID_TO_BIN(uuid) AS lower_bits,
    *
  FROM table1
) AS t1 INNER JOIN (
  SELECT upper_bits, lower_bits, status
  FROM table2
) AS t2 ON t1.upper_bits = t2.upper_bits AND t1.lower_bits = t2.lower_bits

None 已经过测试,但希望它能给您一些想法。