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.status
和 table1.*
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_bits
和 lower_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 已经过测试,但希望它能给您一些想法。
我有一个 uuid 作为人类可读的 guid 存储在一个 table 中,但在另一个 table 中它被分成高位和低位。如何编写查询以加入 uuid 上的 tables?
编辑: table2 给定的高位和低位只会有 1 个结果,所以希望效率不会太差,但请考虑这一点进入答案。
table1.uuid = 'b33ac8a9-ae45-4120-bb6e-7537e271808e'
table2.upper_bits = -5531888561172430560, table2.lower_bits = -4940882858296115058
我需要检索 table2.status
和 table1.*
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_bits
和 lower_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 已经过测试,但希望它能给您一些想法。