如何在 SQL 服务器中生成唯一的数字 ID(不使用标识)?

How to generate a unique numeric ID in SQL Server (not using identity)?

我的 table 需要一个唯一的编号 ID。通常我会在 Sql 服务器中使用 Identity,但我的用例有一个问题。我想在创建行之前知道 id(以便在将所有内容提交到数据库之前能够在内存中的其他记录中引用它)。

我不知道是否可以通过 Identity 实现,但我想不通。

所以我的下一个最佳猜测是我需要一个 table 来存储一个值并不断递增它并返回一个新的 id 值。访问必须被锁定,这样没有两个操作可以获得相同的值。

我正在考虑使用例如sp_getapplock @Resource = 'MyUniqueId' 以防止将相同的号码返回给呼叫者。也许我也可以为此使用普通的事务锁定。

有没有更好的方法来解决这个问题?

此处的一个选项是使用 UUID 来表示每条唯一记录。如果您想在 SQL 服务器中生成 UUID,您可以使用 NEWID() 函数(请参阅 documentation 了解更多信息)。如果此值将从您的应用程序代码生成,您可以使用 CONVERT.

将其转换为 SQL 服务器中的 uniqueidentifier 类型

作为参考,UUID 是一个 16 字节的唯一标识符。您的应用程序或 SQL 服务器 极不可能 多次生成相同的 UUID。它们看起来像这样:

773c1570-1076-4e19-b728-6d7b0b20895a

如果您想要一种与 IDENTITY 列相匹配的行为,请尝试:

CREATE SEQUENCE mydb.dbo.mysequence;

然后,重复:

SELECT NEXT VALUE FOR mysequence;

而且,如果你想玩更多,请看这里:

https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql?view=sql-server-ver15

玩的开心...

您可以创建一个 SEQUENCE 对象来生成增量值。 SEQUENCE 可以独立使用,也可以作为一个或多个 table 的默认值。

您可以使用 CREATE SEQUENCE 创建一个序列:

CREATE SEQUENCE Audit.EventCounter  
    AS int  
    START WITH 1  
    INCREMENT BY 1 ; 

您可以使用 NEXT VALUE FOR 自动检索下一个值并在多个语句中使用它,例如:

DECLARE @NextID int ;  
SET @NextID = NEXT VALUE FOR Audit.EventCounter; 

回滚事务不会影响 SEQUENCE。来自文档:

Sequence numbers are generated outside the scope of the current transaction. They are consumed whether the transaction using the sequence number is committed or rolled back.

您可以在多个 table 中使用 NEXT VALUE FOR 作为默认值。在文档示例中,三种不同类型的事件 table 使用相同的 SEQUENCE 允许所有事件获得唯一编号:

CREATE TABLE Audit.ProcessEvents  
(  
    EventID int PRIMARY KEY CLUSTERED   
        DEFAULT (NEXT VALUE FOR Audit.EventCounter),  
    EventTime datetime NOT NULL DEFAULT (getdate()),  
    EventCode nvarchar(5) NOT NULL,  
    Description nvarchar(300) NULL  
) ;  
GO  
  
CREATE TABLE Audit.ErrorEvents  
(  
    EventID int PRIMARY KEY CLUSTERED  
        DEFAULT (NEXT VALUE FOR Audit.EventCounter),  
    EventTime datetime NOT NULL DEFAULT (getdate()),  
    EquipmentID int NULL,  
    ErrorNumber int NOT NULL,  
    EventDesc nvarchar(256) NULL  
) ;  
GO  
  
CREATE TABLE Audit.StartStopEvents  
(  
    EventID int PRIMARY KEY CLUSTERED  
        DEFAULT (NEXT VALUE FOR Audit.EventCounter),  
    EventTime datetime NOT NULL DEFAULT (getdate()),  
    EquipmentID int NOT NULL,  
    StartOrStop bit NOT NULL  
) ;  
GO