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 ...
是的,所有这些解决方案都不能保证编号中没有漏洞。这可能发生在事务回滚期间(例如死锁)
下面的 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 ...
是的,所有这些解决方案都不能保证编号中没有漏洞。这可能发生在事务回滚期间(例如死锁)