I\'m trying to generate a unique id/timestamp based on the clock of the database server. This is not the main Id of the table, but it\'s in my interest that this value is un
Don't do it. Create a numerical identity
column. For the most part, that will keep track of the order of inserts (this gets a little tricky in multi-threaded environments, but it should be close enough).
Add another column, say createdAt
with a default value of the timestamp. You can make this a datetime2
column for more precision.
If you really need a unique numerical value, I would suggest creating a computed column whose type is something like decimal(38, 10)
. It would have a structure something like this: YYYYMMDDHHMMSSFFFFFF.. ("F" is for fractional seconds.)
First, read all the excellent advice from the comments and other answers about why you probably should do something different.
But, yes you can do this, and here's how. Basically just replace the last few digits of the datetime2 with the values from a sequence. The more digits you replace, the more rows you can insert at the same time without violating the unique constraint. In the example below I'm replacing everything past the 10th of a second with the sequence value. If you wanted to retain more digits of sub-second precision to store the actual clock time at which the insert was attempted, you would just reduce the maximum number of rows you can insert in a batch. So up to you.
Here it is:
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