2009-09-16 63 views
3

好的,我有一個沒有自然鍵的表,只有一個整數標識列作爲主鍵。我想插入和檢索標識值,但也使用觸發器來確保始終設置某些字段。最初,該設計是用來代替插入觸發器,但是打破了scope_identity。插入語句的輸出子句也被插入觸發器取代。所以,我想出了一個替代計劃,並想知道是否有什麼明顯錯誤與我打算做的:SCOPE_IDENTITY而不是插入觸發器解決方案

開始人爲的例子:

CREATE TABLE [dbo].[TestData] (
    [TestId] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL, 
    [Name] [nchar](10) NOT NULL) 

    CREATE TABLE [dbo].[TestDataModInfo](
    [TestId] [int] PRIMARY KEY NOT NULL, 
    [RowCreateDate] [datetime] NOT NULL) 

    ALTER TABLE [dbo].[TestDataModInfo] WITH CHECK ADD CONSTRAINT 
    [FK_TestDataModInfo_TestData] FOREIGN KEY([TestId]) 
    REFERENCES [dbo].[TestData] ([TestId]) ON DELETE CASCADE 

CREATE TRIGGER [dbo].[TestData$AfterInsert] 
    ON [dbo].[TestData] 
    AFTER INSERT 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 
    INSERT INTO [dbo].[TestDataModInfo] 
      ([TestId], 
      [RowCreateDate]) 
     SELECT 
      [TestId], 
      current_timestamp 
     FROM inserted 

    -- Insert statements for trigger here 

END 

末人爲的例子。

不,我沒有這樣做一個小日期字段 - 這只是一個例子。

我想要確保設置的字段已被移動到單獨的表格(在TestDataModInfo中),觸發器確保它已更新。這有效,它允許我在插入後使用scope_identity(),並且看起來是安全的(如果我的after觸發器失敗,我的插入失敗)。這是不好的設計,如果是這樣,爲什麼?

+0

謝謝喬爾 - 沒有看到我自己的馬虎打字。 – 2009-09-16 16:36:27

+0

我假設你正在驗證觸發器中的字段而不是由於遺留數據造成的約束? – Maslow 2010-01-27 13:55:11

+0

@Maslow,觸發器應該是確保某些字段總是或從未更新(updateDate,createdate)的最簡單,最強有力的方法。這些確保您不能違反這些規則,除非您有權禁用觸發器。再一層保護。 – 2010-02-05 13:24:48

回答

2

正如您所提到的,SCOPE_IDENTITY是爲這種情況設計的。與@@ IDENTITY不同,它不受AFTER觸發器代碼的影響。

除了使用存儲的特效,這沒什麼。

我使用AFTER觸發器進行審計,因爲它們很方便...也就是說,寫入我的觸發器中的另一個表。

編輯:SCOPE_IDENTITY and parallelism in SQL Server 2005 cam have a problem

+1

你不能真正說scope_identity不受觸發器代碼的影響 - 如果你使用'而不是insert'觸發器,它將返回null。 – 2009-09-16 16:37:39

+0

@Peter,真的,打字太快了。 – gbn 2009-09-16 16:38:56

0

你試圖使用OUTPUT得到值回呢?

+0

輸出在使用而不是插入觸發器時也返回null。 – 2009-09-16 17:17:15

+0

那麼我想你真的沒有其他選擇,只能使用後觸發。 – HLGEM 2009-09-16 17:27:02

0

您可以在觸發器使用INSTEAD OF觸發器就好了,由剛插入到主表後獲取的值,然後欺騙Scope_Identity()@@Identity在觸發結束:

-- Inside of trigger 
SET NOCOUNT ON; 
INSERT dbo.YourTable VALUES(blah, blah, blah); 
SET @YourTableID = Scope_Identity(); 

-- ... other DML that inserts to another identity-bearing table 

-- Last statement in trigger 
SELECT YourTableID INTO #Trash FROM dbo.YourTable WHERE YourTableID = @YourTableID; 

或者,這裏是一個替代的最後聲明不使用任何讀取,但如果執行用戶沒有權限,可能會導致權限問題(儘管有解決方案)。

SET @SQL = 
    'SELECT identity(smallint, ' + Str(@YourTableID) + ', 1) YourTableID INTO #Trash'; 
EXEC (@SQL); 

注意Scope_Identity()可以在表中返回NULL與INSTEAD在某些情況下,就可以觸發,即使您使用此方法欺騙。但你至少可以使用@@Identity來獲得價值。這可以使MS Access ADP項目在中斷後再次開始工作,因爲您在前端插入的表上放置了觸發器。

此外,要知道,任何並行在所有可以使@@IdentityScope_Identity()返回不正確的值,所以使用OPTION (MAXDOP 1)TOP 1或單排VALUES條款戰勝這個問題。

相關問題