MySql-запрос для объединения uuid, который по-разному хранится в разных таблицах - PullRequest
0 голосов
/ 09 мая 2018

У меня есть uuid, который хранится в одной таблице в виде удобочитаемого гида, но в другой таблице он разбит на верхний и нижний биты. Как я могу написать запрос для объединения таблиц в uuid?

Edit: table2 будет иметь только 1 результат с заданными старшими и младшими битами, так что, надеюсь, эффективность не должна быть слишком ужасной, но, пожалуйста, учтите это в ответах.

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

Мне нужно получить table2.status вместе с table1.*, где table2.upper_bits + table2.lower_bits = table1.uuid (псевдо-оператор where), но я не знаю, как суммировать верхние и нижние значения table2 для объединения или как преобразовать uuid таблицы1 в биты для соединения.

Спасибо!

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

Самый простой способ - сохранить lower_bits & upper_bits в table1 вместе с uuid. Затем объедините таблицы на lower_bits & upper_bits.

Редактировать : Если вам нужна только одна строка, и вы уверены, что в другой таблице будет одна совпадающая строка, рассчитайте 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;
0 голосов
/ 10 мая 2018

Вот вариант решения @ Uueerdo, который должен быть более эффективным (вроде decorate-join-undecorate), но я не запускал EXPLAIN, чтобы знать наверняка:

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

Может потребоваться немного больше памяти, о чем следует помнить, если в таблицах много строк и / или если таблица1 очень широка.

Если вам нужны только записи из таблиц1 и таблиц2, соответствующие одному 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, это будет лучший способ сделать запрос к table2:

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

Ничего из этого не проверено, но, надеюсь, это даст вам некоторые идеи для игры.

0 голосов
/ 09 мая 2018

Нечто подобное может сработать ... но, очевидно, будет крайне неэффективно.

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

... Вы можете использовать верхний / нижний регистр в зависимости от сопоставления / сравнения.


Я бы как-то склонялся к тому, чтобы быть "абсолютно необходимым" для изменения структуры вашей базы данных (чтобы ответить на комментарий, который вы сделали в другом ответе). Чтобы свести к минимуму влияние на существующие запросы и логику, вы можете изменить одну из таблиц, чтобы иметь дополнительные совпадающие поля с другой, и добавить триггеры в таблицу для автоматического заполнения / обновления новых полей; а затем выполните однократное обновление, чтобы установить значения всех старых записей.

Я бы сначала попытался изменить t1, поскольку индекс для двух целых чисел, вероятно, "лучше", чем для одной строки; но я не уверен, насколько простым будет преобразование строки в верхний и нижний биты.

Изменение t2 было бы проще, триггеры были бы немного больше, чем SET NEW.uuid = CONCAT(HEX(NEW.upper_bits), HEX(NEW.lower_bits)); ... Я говорю "немного больше чем", потому что было бы лучше, чтобы триггер также вставил - в также ожидаемые точки, поэтому условие соединения может исключить любое использование функции.


Редактировать: я нашел способ вычисления битов в чистом 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, с которой я проверял вычисления).

...