2010-05-28 13 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