来自字符串的 MSSQL GUID/UUID

MSSQL GUID/UUID from string

我需要使用 MSSQL 从给定的字符串创建永久性的 GUIDs/UUIDs,但找不到解决方法。因此,每次调用函数时,字符串“A12345”都会变成类似“AAAAAAAA-1234-5678-90AB-AAAAAAAAAAA”的内容。 需要一些建议或示例如何实现。

正如有人在评论中所说,您可能应该重新考虑,但是......如果字符串的类型为 varchar(16) 或更小(不是 nvarchar),则至少有一种方法可以大致实现我对您的理解 objective 成为.

我对您的案例了解不多,无法推荐此解决方案,但假设您确实需要这样做。如果不出意外,这可能会帮助您构建自己的功能或共同决定这是一个坏主意。下面的解决方案要求您构建另一个函数,以便在检索数据时基本上反向执行相同的操作,如果您想要返回原始值。

唯一标识符在视觉上由 0-9 和 A-F 之间的 32 个 alpha-numeric 个字符以及四个破折号组成的字符串表示。这意味着该字符串中每个位置有 16 个选项,共 32 个位置。我建议不要在此函数中使用字母 A 作为填充符,下面我使用了 0,因为 00 在 ASCII 中是 NULL,而 AA 将代表一个实际字符。

首先,您可以使用 ASCII() 函数将字符串中的每个字符转换为其 ASCII 值。此后,您可以通过对该值使用除法和模数 16,将返回的整数转换为十六进制字符串表示形式。 SQL Server 中的 ASCII 范围是 0-255,这意味着有 256 个不同的字符。 256 是 16 乘以 16,这意味着您需要 uniqueidentifier 中的两个位置来表示输入字符串中的每个字符,因此此函数中的最大字符串限制为 16 个而不是 32 个(请参阅前面的段落)。最后,您需要在正确的位置插入破折号并将字符串转换为唯一标识符。

 CREATE FUNCTION dbo.MYGUID (@input varchar(17))
    RETURNS uniqueidentifier
    BEGIN
        /* Unable to convert any string langer than 16 characters with this method */
        IF LEN(@input) > 16
            RETURN CAST('FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF' as uniqueidentifier)
    
    DECLARE 
        @result varchar(36) = '',
        @char char(1) = '',
        @placeholder varchar(32) = REPLICATE('0',32)

    /* Convert all characters in string to psuedo-hexadecimal */
    WHILE LEN(@input) > 0 BEGIN
        /* Use first character in input string.. */
        SET @char = LEFT(@input, 1)
        /* Convert character to hexadecimal representation */
        SET @result += CONVERT(char(1),
            CASE ASCII(@char) / 16
                WHEN 10 THEN 'A'
                WHEN 11 THEN 'B'
                WHEN 12 THEN 'C'
                WHEN 13 THEN 'D'
                WHEN 14 THEN 'E'
                WHEN 15 THEN 'F'
                ELSE CONVERT(char, ASCII(@char) / 16)
            END)
        +CONVERT(char(1), 
            CASE ASCII(@char) % 16
                WHEN 10 THEN 'A'
                WHEN 11 THEN 'B'
                WHEN 12 THEN 'C'
                WHEN 13 THEN 'D'
                WHEN 14 THEN 'E'
                WHEN 15 THEN 'F'
                ELSE CONVERT(char, ASCII(@char) % 16)
            END
        )
        /* Remove first character from input string.. */
        SET @input = STUFF(@input, 1, 1, '')
    END

    /* Make sure there are exactly 32 alpha-numeric characters in outgoing string */
    SET @result = RIGHT(@placeholder+@result,32)

    /* Insert dashes at the correct positions */
    SET @result = STUFF(@result, 21, 0, '-')
    SET @result = STUFF(@result, 17, 0, '-')
    SET @result = STUFF(@result, 13, 0, '-')
    SET @result = STUFF(@result, 9, 0, '-')

    /* Returns string as uniqueidentifier */
    RETURN CAST(@result as uniqueidentifier)
END

创建函数后,您可以使用它..

SELECT dbo.MYGUID(column1)
FROM table1

..或..

SELECT dbo.MYGUID('A12345')

如果您只是想创建一个映射,您可以这样做 (example fiddle):

创建一个 table 来保存映射

create table StringGuidMap (
    Guid uniqueidentifier not null constraint PK_StringGuidMap primary key clustered default NewSequentialId()
    , StringId nvarchar(8) not null constraint UK_StringGuidMap_StringId unique
)

创建逻辑以获取映射或根据需要创建新映射:

create procedure sp_GetIdMapping (
  @StringId nvarchar(8)
) as
begin

  declare @result uniqueidentifier = null

  select @result = Guid 
  from StringGuidMap 
  where StringId = @StringId -- note: case/accent sensitivity depends on your DB's collation

  if (@result is null)
  begin
      
      insert into StringGuidMap(StringId) 
      values (@StringId)
      
      select @result = Guid 
      from StringGuidMap 
      where StringId = @StringId
      
  end

  select @result Guid

end

在上面我使用 NewSequentialId 生成 GUID,确保此列可以轻松用作主键/在索引中而不会导致碎片,因为生成的每个新 ID 都将被放置在现有索引的末尾。但是,如果您愿意/可以在存储过程中生成 GUID 而不是作为插入中的默认值,则可以使用 newid() 生成 GUID,从而减少那里的调用。选择哪种取决于您的要求

注:以上为映射;但是这种映射只对具有映射 table 的人有意义/这不是普遍适用的东西;还是那句话,这个是不是suitable要看你的要求了