【问题标题】:Increment a uniqueidentifier in TSQL在 SQL 中增加唯一标识符
【发布时间】:2010-10-23 18:14:44
【问题描述】:

我正在寻找一种在 TSQL 中将 uniqueidentifier 递增 1 的方法。例如,如果 id 是 A6BC60AD-A4D9-46F4-A7D3-98B2A7237A9E,我希望能够选择 A6BC60AD-A4D9-46F4-A7D3-98B2A7237A9F。

@rein 用于数据导入。我们有一个中间表,其中包含我们从中生成记录的 ID,我们稍后会在导入时加入这些 ID。不幸的是,现在其中一些记录在下一个表中生成了几条记录,因此我们需要一个可重现的新 id。

【问题讨论】:

  • 我真的很想知道您为什么需要这样做。
  • 如果您发现自己处于需要增加 GUID 的情况,10 次中有 9 次我会重新检查您正在尝试做的事情。
  • 与其增加 GUID,也许只添加一个额外的序列列来消除歧义会更简单?
  • 所以,它们应该是“随机的”,因为它们在全球范围内是唯一的……为什么要让 next GUID 的生成可预测?

标签: sql-server tsql uniqueidentifier


【解决方案1】:

您想要增加 Guid 的方式对于 SQL Server 是不正确的,因为 Guid 是一个在字节组中具有不同字节顺序的结构,请查看: http://sqlblog.com/blogs/alberto_ferrari/archive/2007/08/31/how-are-guids-sorted-by-sql-server.aspx 并注意以下几点:

现在,当我运行修改后的 Alberto 查询时,我得到以下序列: 3、2、1、0、5、4、7、6、9、8、15、14、13、12、11、10

这意味着,GUID 的字节 #3 是最不重要的,而 GUID 的字节 #10 是最重要的 [从 SQL Server ORDER BY 子句的角度来看]。

这里有一个简单的函数来增加一个uniqueidentifier来说明这一点:

create function [dbo].[IncrementGuid](@guid uniqueidentifier) 
returns uniqueidentifier 
as 
begin 
declare @guid_binary binary(16), @b03 binary(4), @b45 binary(2), @b67 binary(2), @b89 binary(2), @bAF binary(6)

select @guid_binary = @guid

select @b03 = convert(binary(4), reverse(substring(@guid_binary,1,4)))
select @b45 = convert(binary(2), reverse(substring(@guid_binary,5,2)))
select @b67 = convert(binary(2), reverse(substring(@guid_binary,7,2)))
select @b89 = convert(binary(2), substring(@guid_binary,9,2))
select @bAF = convert(binary(6), substring(@guid_binary,11,6))

if (@b03 < 'FFFFFFFF')
begin
    select @b03 = convert(binary(4), cast(@b03 as int) + 1)
end
else if (@b45 < 'FFFF')
begin
    select @b45 = convert(binary(2), cast(@b45 as int) + 1)
end
else if (@b89 < 'FFFF')
begin
    select @b89 = convert(binary(2), cast(@b89 as int) + 1)
end
else
begin
    select @bAF = convert(binary(6), cast(@bAF as bigint) + 1)
end

return convert(binary(16), reverse(convert(char(4),@b03)) + reverse(convert(char(2),@b45)) + reverse(convert(char(2),@b67)) + convert(char(2),@b89) + convert(char(6),@bAF))
end 

请注意,字节 6 和 7 不递增,因为它们包含 Guid 版本位。 但正如其他人指出的那样,您真的不应该这样做。在您的情况下,为这些 Guid 创建一个临时表可能会更好(有两列:一个整数作为索引,第二个带有生成的 Guid)。

【讨论】:

    【解决方案2】:

    你可以这样做,但我没有考虑溢出低 8 个字节的情况。

    declare @guid uniqueidentifier, @binaryUpper8 binary(8), @binaryLower8 binary(8), @binary16 binary(16), @bigint bigint
    set @guid = 'A6BC60AD-A4D9-46F4-A7D3-98B2A7237A9E'
    set @binary16 = cast(@guid as binary(16))
    
    --harvest lower 8 bytes
    select @binaryUpper8= substring(@binary16, 1, 8)
        ,@binaryLower8  = substring(@binary16, 9, 8)
    set @bigint = cast(@binaryLower8 as bigint)
    
    --increment
    set @bigint = @bigint + 1
    
    --convert back
    set @binaryLower8 = cast(@bigint as binary(8))
    set @binary16 = @binaryUpper8 + @binaryLower8
    set @guid = cast(@binary16 as uniqueidentifier)
    select @guid
    

    【讨论】:

      【解决方案3】:

      这是我想出的一种方法,但我希望有更好的方法。

      LEFT([ID], 19) + RIGHT(CONVERT(uniqueidentifier, CONVERT(binary(16), CONVERT(binary(16), [ID]) + CONVERT(bigint, 1))), 17) AS 'MyNewID'
      

      【讨论】:

      • 什么版本的sql server; 2005 和 2008 具有递增的唯一标识符作为数据函数 - NEWSEQUENTIALID()
      • 我也希望这也是我的答案,但不幸的是它不能用于查询。
      • 如果你可以使用 clr 那么你可以试试这个jorriss.net/blog/jorriss/archive/2008/04/24/…
      猜你喜欢
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-08
      相关资源
      最近更新 更多