我有一个带有ID(标识)和XID(int)的表,这是我的自定义自动增量列。我正在使用而不是插入触发器来维护XID,但我得到了重复。
表格
xtable(ID identity,XID int)
触发器 - 而不是插入
insert into [xtable] (XID)
select [x].[NextavailableID]
from inserted [i]
cross apply
(
select coalesce(max([t].[XID]), 0) + 1 [NextavailableID]
from [xtable] [t]
) [x];
假设插入= 1行。
此触发器不会阻止XID列中的重复项。关于如何改变它的任何想法?
答案 0 :(得分:2)
问题是,如果您要插入多行,则所有行都使用相同的下一个可用ID,您需要添加ROW_NUMBER()
以确保插入中的xid是唯一的:
insert into [xtable] (XID)
select [x].[NextavailableID] + ROW_NUMBER() OVER (ORDER BY i.ID)
from inserted [i]
cross apply
(
select coalesce(max([t].[XID]), 0) [NextavailableID]
from [xtable] [t] WITH (TABLOCK, HOLDLOCK)
) [x];
关于防止重复,您可以在获得最大xtable
时使用表提示锁定xid
。
使用这些锁的缺点是你会遇到死锁。您应该在此列上具有唯一约束/索引,因为这将防止重复,但是当满足竞争条件时它也将导致异常。最终,无论你选择何种方法,你都需要做出某种牺牲。
答案 1 :(得分:1)
SQL Server 2012 +:
我会使用sequences。
首先,我会创建一个新序列
CREATE SEQUENCE dbo.XTable_XID
START WITH 1 -- You should replace the starting value
INCREMENT BY 1
-- CACHE 50; -- Optimization: read documentation first
GO
然后我会使用NEXT VALUE FOR生成新值:
-- #1 I would use this function when I insert rows `into dbo.XTable`
INSERT INTO [dbo].[XTable] (Col1, Col2, Col3, ..., XID)
VALUES ('A', 123, 1000.50, (NEXT VALUE FOR dbo.XTable_XID));
或
-- #2: Also, you could rewrite the trigger thus:
insert into [xtable] (XID)
select (NEXT VALUE FOR dbo.XTable_XID)
from inserted [i]
我正在使用第一种方法,如果它仅用于生成这些ID,则可以删除该触发器。我会使用解决方案#1。
+
我会创建一个唯一的索引:
CREATE UNIQUE INDEX IUN_XTable_XID
ON dbo.XTable (XID);
答案 2 :(得分:1)
我最终创建了另一个表来存储最后一个增量。在触发器中,在事务内部,我从新表中选择提示(UPDLOCK
,ROWLOCK
)。
表格强>
Info (LastId int)
触发器 - 而不是插入
declare @nextId int;
begin tran t1
set @nextId = (select top 1 LastId from Info with (UPDLOCK, ROWLOCK)) + 1;
update Info set LastId = nextId;
commit tran t1
insert into [xtable] (XID)
select @nextId
from inserted [i]