SQL 服务器:自动为一次插入的所有行添加唯一标识符

SQL Server: automatically add a unique identifier to all rows inserted at one time

下面的 SQL 服务器代码成功计算并插入所有员工的月薪及其 staffID 编号,并将其插入 Tablepayroll.

INSERT INTO Tablepayroll (StaffID,Totalpaid)
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay
FROM Tabletimelog 
JOIN Tablestaff ON
Tabletimelog.StaffID = Tablestaff.StaffID)

不过,我希望也能插入一个batchID,这样你就可以识别出每次上面的insert已经运行以及它当时插入的记录。这意味着同时计算的所有员工工资单将具有相同的 batchID 数字。每个后续 batchID 应该只增加 1。

请参阅下图进行直观解释。

我认为 Select MAX(batch_id) + 1 可以,但我不知道如何将它包含在插入语句中。

您可以使用子查询从当前的 table 中查找最新的 batch_id,使用此查询:

INSERT INTO TablePayroll (StaffID, TotalPaid, batch_id)
SELECT T1.StaffID
  , T1.HoursWorked * T2.HourlyPay
  , ISNULL((SELECT MAX(batch_id) FROM TablePayRoll), 0) + 1 AS batch_id
FROM TableTimeLog AS T1
INNER JOIN TableStaff AS T2
  ON T1.StaffID = T2.StaffID;

如您所见,我只是将当前值加 1 MAX(batch_id) 就这样。
顺便说一句,学会使用别名。它会让你的生活更轻松

另一种解决方案是将您的 batch_id 作为 GUID,这样您就不必创建序列或从当前 table.

获取 MAX(batch_id)
DECLARE @batch_id UNIQUEIDENTIFIER = NEWID();

INSERT INTO TablePayroll (StaffID, TotalPaid, batch_id)
SELECT T1.StaffID, T1.HoursWorked * T2.HourlyPay, @batch_id
FROM TableTimeLog AS T1
INNER JOIN TableStaff AS T2
  ON T1.StaffID = T2.StaffID;

已更新

首先获取一个大table中的最大值(根据名字table它一定是大的)会非常昂贵。特别是如果 batch_id

列上没有索引

其次,请注意您的解决方案 SELECT MAX(batch_id) + 1 可能会在您有竞争性插入时表现不正确。来自 @EvaldasBuinauskas 的解决方案没有打开事务和正确的隔离级别也可以导致相同的 batch_id 如果你 运行 同时并行插入两个。

如果您的 SQL 服务器版本为 2012 或更高版本,您可以尝试 SEQUENCE。这至少确保没有重复 batch_id

正在创建 SEQUENCE

CREATE SEQUENCE dbo.BatchID
    START WITH 1  
    INCREMENT BY 1 ;  
-- DROP SEQUENCE dbo.BatchID
GO  

并使用它:

DECLARE @BatchID INT
SET @BatchID =  NEXT VALUE FOR dbo.BatchID;

INSERT INTO Tablepayroll (StaffID,Totalpaid, batch_id)
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay, @BatchID
    FROM Tabletimelog 
        JOIN Tablestaff ON  Tabletimelog.StaffID = Tablestaff.StaffID)

备选 SEQUENCE 可能是额外的 table:

CREATE TABLE dbo.Batch (
    ID INT NOT NULL IDENTITY 
        CONSTRAINT PK_Batch PRIMARY KEY CLUSTERED
    ,DT DATETIME
        CONSTRAINT DF_Batch_DT DEFAULT GETDATE()
);

此解决方案甚至适用于旧版本的服务器。

DECLARE @BatchID INT

INSERT INTO dbo.Batch (DT)
    VALUES (GETDATE());

SET @BatchID = SCOPE_IDENTITY();

INSERT INTO Tablepayroll (StaffID,Totalpaid, batch_id)
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay, @BatchID
    FROM Tabletimelog ...

是的,所有这些解决方案都不能保证编号中没有漏洞。这可能发生在事务回滚期间(例如死锁)