如何在事务完成之前获取使用标识列值?

时间:2013-04-22 18:41:00

标签: sql tsql transactions sql-server-2008-r2

假设我的数据库中有3个表,如下所示:

  • Personpersonid,...)---这是实体,personid是标识列
  • Phonephoneid,...)---这是实体,phoneid是标识列
  • PersonPhonepersonid, phoneid)---这段关系

当我将数据插入表中时,我需要先在实体表中插入行并获取生成的id,然后我需要在关系表中插入一行。

工作正常。问题是:我有一个带有Try Catch语句的事务的存储过程,如:

BEGIN TRY
declare aCursor cursor local fast_forward for (Select Query...)

open aCursor;
fetch next from aCursor into @variables....

while @@fetch_status = 0
begin

   INSERT INTO Person(...);
   set @personid =@@IDENTITY;

   INSERT INTO Phone(...);
   set @phoneid =@@IDENTITY;

   INSERT INTO PersonPhone(@personid, @phoneid);       
end; 

END TRY
BEGIN CATCH
    close aCursor;
    deallocate selectdistributor;
     SELECT ERROR_NUMBER() AS ErrorNumber,ERROR_MESSAGE() AS ErrorMessage;    
    ROLLBACK TRAN;
    RETURN;
END CATCH  
COMMIT;  
close aCursor;
deallocate aCursor;

使用光标,会为人,手机插入更多的记录。运行SP时,它将在关系中第一次插入数据时停止。另外我可以正确@personid,@ phoneid,但在交易完成之前,我在INSERT INTO PersonPhone(@personid,@ phoneid)上收到错误;为:

  

INSERT语句与FOREIGN KEY约束“Person_PersonPhone_FK1”冲突。冲突发生在数据库“MYDB”,表“dbo.Person”,列'PersonID'。

在事务完成之前看起来系统生成的Id无法识别。

如何解决此问题?

1 个答案:

答案 0 :(得分:0)

可能你的问题是你使用了@@ identity,在任何情况下都不应该用于此目的。如果其中一个表具有触发器,则可以返回错误的值(触发器插入的表中的标识),并且该值在外键链接到的表中不存在。

所以假设你有一个触发onteh的第一个表,它将iunserts带到一个带有标识的审计表。插入ID为1234的记录。将tirigger插入到不同的表中,因此由@@ Identity重新标记的值为5678,它不存在于原始表中。当您在第一个表上使用FK插入到表中时,您会收到错误消息,因为第一个表中不存在值5678。

请改用OUTPUT子句。您也可以使用scope_identity(),但输出更灵活(并允许您执行多个记录插入并接收所有标识以及可能唯一标识记录的其他字段。

我和Aaron在一起,除非有人威胁我的生命,否则我不会用光标。