2010-05-28 23 views
4

我有一个需要日志ID的日志记录表,但我不能使用标识列,因为日志ID是组合键的一部分。模拟插入触发器内的标识列

create table StuffLogs 
{ 
    StuffID int 
    LogID int 
    Note varchar(255) 
} 

没有为StuffID & LogID组合键。

我想建立一个插入触发器,当插入日志记录时计算下一个LogID。我可以一次完成一条记录(请参阅下面的内容以了解如何计算LogID),但这并不是很有效,我希望有一种方法可以在不使用游标的情况下执行此操作。

select @NextLogID = isnull(max(LogID),0)+1 
from StuffLogs where StuffID = (select StuffID from inserted) 

最终结果应该允许我插入任意数量的记录到自动计算的LogID列的StuffLog中。

StuffID LogID Note 
123  1  foo 
123  2  bar 
456  1  boo 
789  1  hoo 

使用StuffID: 123, Note: bop将导致以下记录插入另一个记录:

StuffID LogID Note 
123  3  bop 

回答

0
Select Row_Number() Over(Order By LogId) + MaxValue.LogId + 1 
From inserted 
    Cross Join (Select Max(LogId) As Id From StuffLogs) As MaxValue 

您将需要彻底测试这一点,并保证如果两个连接在相同的插入到表你不会在LogId上发生冲突。

+0

你可能会想包装成这个BEGIN TRANSACTION ... END TRANSACTION,甚至可能是SET交易的IsolationLevel SERIALIZABLE开始与 - 只是为了确保没有两个连接可以在同一时间更新并获得相同的新ID返回 – 2010-05-28 17:27:39

+0

@marc_s - 同意。这显然会对并发造成一些有害影响。 – Thomas 2010-05-28 17:32:19

+0

>从StuffLogs中选择最大(Id)作为Id 1.您可以找到全局最大值,但不能插入StuffID。 (例如: )插入到StuffLogs(staffid,not)值(123,'a'),(123,'b'),... – msi77 2010-05-28 17:47:26

3

除非有一个严格的商业原因,要求每个LogID都是从1开始的序列,对于每个不同的StuffID,则只需使用一个标识。通过身份,您仍然可以使用StuffID + LogID正确地排序行,但是您不会尝试手动执行插入问题(并发,死锁,锁定/阻塞,缓慢插入等)。

+1

仅仅因为它是组合键的一部分并不意味着它不能成为一个身份。 – HLGEM 2010-06-01 20:07:23

0

确保LogId的默认值为NULL,以便在插入语句期间不需要提供它,例如它是标识列。

CREATE TRIGGER Insert ON dbo.StuffLogs 
INSTEAD OF INSERT 
AS 
UPDATE #Inserted SET LogId = select max(LogId)+1 from StuffLogs where StuffId=[INSERTED].StuffId