一尘不染

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

sql

我正在尝试根据数据库服务器的时钟生成唯一的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

阅读 192

收藏
2021-03-17

共1个答案

一尘不染

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

但是,是的,您可以执行此操作,这就是方法。基本上,只需将序列中的值替换为datetime2的最后几位。您替换的位数越多,您可以在不违反唯一约束的情况下同时插入更多的行。在下面的示例中,我将超过10秒的所有内容替换为序列值。如果要保留更多的亚秒级精度来存储尝试插入的实际时钟时间,则只需减少可批量插入的最大行数。所以取决于你。

这里是:

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
2021-03-17