好的,我有一个没有自然键的表,只有一个整数标识列作为它的主键。我想插入和检索标识值,但也使用触发器来确保始终设置某些字段。最初,设计是使用而不是插入触发器,但这会破坏scope_identity。 insert语句中的output子句也被insert而不是insert触发器打破。所以,我想出了一个替代计划,想知道我打算做什么有明显的错误:
开始做出例子:
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(),并且看起来是安全的(如果我的后触发失败,我的插入失败)。这是不好的设计,如果是这样,为什么?
答案 0 :(得分:3)
正如您所提到的,SCOPE_IDENTITY是针对这种情况而设计的。与@@ IDENTITY不同,它不受AFTER触发代码的影响。
除了使用存储过程之外,这没关系。
我使用AFTER触发器进行审核,因为它们很方便......也就是说,写入触发器中的另一个表。
修改:SCOPE_IDENTITY and parallelism in SQL Server 2005 cam have a problem
答案 1 :(得分:0)
您是否尝试过使用OUTPUT来取回值?
答案 2 :(得分:0)
您是否尝试过使用:
SELECT scope_identity();
http://wiki.alphasoftware.com/Scope_Identity+in+SQL+Server+with+nested+and+INSTEAD+OF+triggers
答案 3 :(得分: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()
在某些情况下可能会在具有INSTEAD OF触发器的表上返回NULL,即使您使用此欺骗方法也是如此。但你至少可以使用@@Identity
获得价值。这可以使MS Access ADP项目在中断后再次开始正常工作,因为您在前端插入的表上放置了一个触发器。
另外,请注意,任何并行操作都会导致@@Identity
和Scope_Identity()
返回不正确的值 - 因此请使用OPTION (MAXDOP 1)
或TOP 1
或单行{{1 }}子句来解决这个问题。