在 SQL Server 中的表上生成唯一的基于时间的 id

0 sql t-sql sql-server

我正在尝试根据数据库服务器的时钟生成唯一的 ID/时间戳。这不是表的主 ID,但我感兴趣的是该值对于每一行都是唯一的。该代码位于一个存储过程中,该存储过程将由同时运行的各个进程同时执行。

我已经想出了这段代码,但找不到让它更优雅的方法。据我测试,确保其他进程不会在其他线程上生成相同值的唯一方法是在检查是否存在时锁定表。

DECLARE @CurrentRRN varchar(30)
SET @CurrentRRN = FORMAT(SYSDATETIME(), 'yyyyMMddHHmmssffffff')

IF(EXISTS(SELECT RRN FROM dbo.Numbering WITH (xlock, tablockx, holdlock) 
  WHERE RRN = @CurrentRRN)) BEGIN

  WHILE( EXISTS(SELECT RRN FROM dbo.Numbering WHERE RRN = @CurrentRRN) )
    BEGIN
        SET @CurrentRRN = FORMAT(SYSDATETIME(), 'yyyyMMddHHmmssffffff')
    END

END

INSERT INTO dbo.Numbering
(RRN)
Values
(@CurrentRRN)

print @CurrentRRN
Run Code Online (Sandbox Code Playgroud)

Dav*_*oft 6

首先,阅读评论和其他答案中的所有精彩建议,了解为什么您可能应该做一些不同的事情。

但是,是的,您可以做到这一点,具体方法如下。基本上只需将 datetime2 的最后几位替换为序列中的值即可。替换的数字越多,在不违反唯一约束的情况下可以同时插入的行就越多。在下面的示例中,我将用序列值替换超过十分之一秒的所有内容。如果您想保留更多的亚秒精度数字来存储尝试插入的实际时钟时间,您只需减少可以在批次中插入的最大行数即可。所以由你决定。

这里是:

drop table if exists MyTableWithUniqueDatetime2

drop sequence if exists seq_ts_nanoseconds
go
create sequence seq_ts_nanoseconds
start with 0 
increment by 100
minvalue 0
maxvalue 99999900
cycle

go
create or alter function GetTimestamp(@ts datetime2, @ns int)
returns datetime2(7)
as
begin
 return  dateadd(ns,@ns, dateadd(ns,-(datepart(ns,@ts) % 100000),@ts))
end
go
create table MyTableWithUniqueDatetime2
(
  id bigint identity,
  a int,
  b int,
  ts datetime2(7) default dbo.GetTimestamp(sysdatetime(), (next value for seq_ts_nanoseconds)) unique

)
go
select sysdatetime()
insert into MyTableWithUniqueDatetime2 (a,b)
output inserted.*
select top (1000) 1,2
from sys.objects o, sys.columns c, sys.columns c2
Run Code Online (Sandbox Code Playgroud)