2009-09-16 40 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条款战胜这个问题。

相关问题