我使用的是SQL Server 2008 R2。
我正在寻找一种我描述为依赖身份的功能。
我将以一个例子来解释。
考虑这样一个表:
脚本
CREATE TABLE [dbo].[Rooms](
[RoomID] [int] NOT NULL,
[ItemID] [int] NOT NULL,
[ItemDescription] [nvarchar] (250))
GO
数据:
RoomID ItemID ItemDescription
------ ------ ---------------
7 1 Door
7 2 Window (West)
7 3 Window (North)
8 1 Door
8 2 Table #1
8 3 Table #2
7 4 Table #1
8 4 Chair #1
7 5 Table #2
7 6 Table #3
8 5 Chair #2
(有人能告诉秘密如何格式化示例表吗?)
我希望能够像这样声明一个依赖的标识列:
ItemID [int] Identity(RoomID,1,1) NOT NULL
[Rooms]
中的新行应触发对ItemID
RoomID
的最大值的测试,其中@roomID
= RoomID
并添加1。
使用删除并插入所需数据,而不是使用DECLARE @roomID INT
SET @roomID = 7
INSERT INTO [Allocation].[dbo].[Rooms]
([RoomID], [ItemID], [ItemDescription]) VALUES (@roomID,
(SELECT max([ItemID])+1 FROM [Allocation].[dbo].[Rooms] WHERE [RoomID]=@roomID)
,'Chair #1')
GO
中的更改进行更新。
现在我以编程方式执行此操作:
{{1}}
那么,有这样的功能吗?
在可能的情况下没有,在给定特定的表,父列和从属标识列的情况下,我可以自动编程服务器为我设置下一个从属身份吗?
答案 0 :(得分:1)
您可以使用触发器和索引来提高性能并确保没有重复项。
将表更改为具有主键,并为ItemID
允许nullCREATE TABLE [dbo].[Rooms](
[RoomID] [int] NOT NULL,
[ItemID] [int] NULL,
[ItemDescription] [nvarchar](250) NULL,
[Id] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_Rooms] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
)
然后添加触发器
CREATE TRIGGER RoomTrigger
ON Rooms
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
update Rooms
set
ItemID = (select coalesce(MAX(itemid), 0) + 1
from Rooms r where r.RoomID = inserted.RoomID )
from
inserted where Rooms.Id = inserted.Id
END
然后你可以这样做
insert into Rooms (RoomID, ItemDescription) values (1, 'Test')
insert into Rooms (RoomID, ItemDescription) values (1, 'Test')
导致
RoomID ItemID ItemDescription Id
2 0 Test 1
2 1 Test 2
正如marc_s所建议的那样,我使用SQL Query Stress和10个线程来查看加载时此触发器会发生什么。我没有得到任何重复项(使用默认的隔离级别),但我确实得到了大量的死锁,正如我所期望的那样。
使用问题中的原始查询,我得到了很多重复。
使用触发器方法我会遇到死锁和结果:
RoomID ItemID ItemDescription Id
1 6 Test 6
1 7 Test 9
1 8 Test 902
1 9 Test 903
此处ItemID是连续的,但是1000行中约有900行未能插入,在Id中留下较大的间隙。
如果我们添加以下索引:
CREATE UNIQUE NONCLUSTERED INDEX [IX_Rooms] ON [dbo].[Rooms]
(
[RoomID] ASC,
[ItemID] ASC
)
为了保证没有重复,并提高计算特定RoomID的Max(ItemId)的性能,那么现在:
使用具有隔离级别= serializable的触发器会导致死锁,因此只有40%的插入成功(但由于重复而没有例外)。
作为最终测试尝试使用触发器+50个线程+隔离级别=默认值。 没有错误。