Как создать детерминированный уникальный идентификатор (GUID) из целочисленного значения - PullRequest
0 голосов
/ 28 августа 2018

Примечание. Речь идет не о разработке базы данных и не об общем использовании GUID. Речь идет о детерминированном создании таких GUID для тестовых данных на сервере Microsoft SQL.

Мы переносим нашу базу данных из целочисленных идентификаторов в тип данных uniqueidentifier.

В целях тестирования мы хотим перенести наши наборы тестовых данных в известные значения GUID, детерминистически основанные на наших прежних целочисленных значениях

UPDATE Unit
SET UnitGuid = NEWID(UnitId)

Очевидно, это не работает сразу. Как использовать UnitId для создания детерминированного GUID?

Ответы [ 3 ]

0 голосов
/ 29 августа 2018

В итоге я решил это для себя. Вот мое решение для дальнейшего использования:

Я создаю префиксную часть GUID в виде deadbeef-0000-0000-0000-, затем добавляю к нему «строковую», дополненную нулями версию целочисленного значения столбца Id, например 000000000001, что приводит к

DEADBEEF-0000-0000-0000-000000000001

в этом примере.

Вот команда SQL для этого действия для всей таблицы:

-- Deterministically creates a uniqueidentifier value out of an integer value. 
DECLARE @GuidPrefix nvarchar(max) = N'deadbeef-0000-0000-0000-';  -- without the last 12 digits
UPDATE Unit 
    SET UniqueColumn = 
    (SELECT @GuidPrefix + RIGHT('000000000000' + CAST(IntegerId AS NVARCHAR (12)), 12 ) AS NUMBER_CONVERTED)

Предупреждения:

  • Эта реализация работает только для положительных значений int (которые работают до 2147483647 макс.)
  • Это только для тестовых данных! Использование это настоятельно не рекомендуется для производственных данных!

А вот полный рабочий пример:

-- Create an example table with random GUID's
CREATE TABLE Unit
(
UniqueColumn UNIQUEIDENTIFIER DEFAULT NEWID(),
Characters VARCHAR(10),
IntegerId int
)

-- Add 2 data rows
INSERT INTO Unit(Characters, IntegerId) VALUES ('abc', 1111)
INSERT INTO Unit(Characters, IntegerId) VALUES ('def', 2222)

-- Deterministically creates a uniqueidentifier value out of an integer value. 
DECLARE @GuidPrefix nvarchar(max) = N'deadbeef-0000-0000-0000-';  -- without the last 12 digits
UPDATE Unit 
    SET UniqueColumn = 
    (SELECT @GuidPrefix + RIGHT('000000000000' + CAST(IntegerId AS NVARCHAR (12)), 12 ) AS NUMBER_CONVERTED)

-- Check the result
SELECT * FROM Unit

Результат:

UniqueColumn                            Characters IntegerId
--------------------------------------- ---------- ---------
DEADBEEF-0000-0000-0000-000000001111    abc        1111
DEADBEEF-0000-0000-0000-000000002222    def        2222
0 голосов
/ 29 августа 2018

Хватит думать о проблеме с «строковой» точки зрения . int состоит из 4 байтов. A uniqueidentifier состоит из 16 байтов. Вы можете легко взять 12 фиксированных байтов и добавить четыре байта от int к их окончанию, и получить решение, которое работает для всех значений int:

declare @Unit table
(
UniqueColumn UNIQUEIDENTIFIER DEFAULT NEWID(),
Characters VARCHAR(10),
IntegerId int
)

-- Add *3* data rows
INSERT INTO @Unit(Characters, IntegerId) VALUES ('abc', 1111),('def', 2222),('ghi',-17)

-- Deterministically creates a uniqueidentifier value out of an integer value. 
DECLARE @GuidPrefix binary(12) = 0xefbeadde0000000000000000
UPDATE @Unit 
    SET UniqueColumn = CONVERT(uniqueidentifier,@GuidPrefix + CONVERT(binary(4),IntegerId))

-- Check the result
SELECT * FROM @Unit

Результат:

UniqueColumn                         Characters IntegerId
------------------------------------ ---------- -----------
DEADBEEF-0000-0000-0000-000000000457 abc        1111
DEADBEEF-0000-0000-0000-0000000008AE def        2222
DEADBEEF-0000-0000-0000-0000FFFFFFEF ghi        -17

(По разным причинам мы должны предоставить первые четыре байта в порядке, отличном от того, который используется по умолчанию при отображении uniqueidentifier в виде строки, поэтому, если мы хотим отобразить DEADBEEF, мы должны были начать наш двоичный файл как efbeadde)

Также, конечно, вставьте обычные предупреждения о том, что если вы создаете guids / uniqueidentifiers, но не используете один из предписанных методов их генерации, то вы не можете принять какие-либо обычные гарантии уникальности.

0 голосов
/ 28 августа 2018

Вы можете создать таблицу раскладок:

CREATE TABLE tab_map(id_old INT PRIMARY KEY, guid UNIQUEIDENTIFIER);

INSERT INTO tab_map(id_old, guid)
SELECT id, NEWID()
FROM src_table;

Демоверсия DBFiddle

После этого вы можете использовать простой запрос или перенос с функцией:

SELECT guid
FROM tab_map
WHERE id_old = ?
...