问题
I have a table with ID (identity) and XID (int) which is my custom auto increment column. I am using an instead of insert trigger to maintain XID, but I am getting duplicates.
table
xtable (ID identity, XID int)
trigger - instead of insert
insert into [xtable] (XID)
select [x].[NextavailableID]
from inserted [i]
cross apply
(
select coalesce(max([t].[XID]), 0) + 1 [NextavailableID]
from [xtable] [t]
) [x];
Assuming inserted = 1 row.
This trigger doesn't prevent duplicates in the XID column. Any ideas on how to change it?
回答1:
The problem is that where you have multiple rows being inserted you are using the same next available ID for all rows, you'd need to add ROW_NUMBER() in to ensure the xid was unique in the insert:
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];
With regard to preventing duplicates you can use table hints to lock xtable when getting the maximum xid.
The drawback of using these locks is that you will get deadlocking. You should have a unique constraint/index on this column as this will prevent duplicates, however it will also result in exceptions when a race condition is met. Ultimately, whatever method you choose you will need to make some kind of sacrifice.
回答2:
I ended up creating another table to store the last increment. In the trigger, inside a transaction, I select from the new table with hints (UPDLOCK, ROWLOCK).
table
Info (LastId int)
trigger - instead of insert
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]
来源:https://stackoverflow.com/questions/24267505/maintaining-a-custom-auto-increment-column