Scope_Identity() 在表中插入第一行后返回 null

4 sql-server identity sql-server-2012

我有一个用于在两个表中插入值的存储过程。

这些表具有父子关系,即第一个表具有标识列,第二个表引用第一个表。

在以下过程中,我将Scope_Identity()值作为列返回:

ALTER PROCEDURE [dbo].[Insert_Header_Details_Tables]
    (
        @ProcessID [int]=null, 
        @FileName [varchar](50)=null,
        @VendorName [varchar](250)=null, 
        @LastName [nvarchar](100)=null,
        @FirstName [nvarchar](100)=null,
        @isFirstMSH [bit]
    )    
AS
--BEGIN TRANSACTION 
-- Insert into Jobs table
IF(@isFirstMSH = 1)
BEGIN
INSERT INTO LabStagingHeader
             ([FileName], 
             [VendorName] 
            ) 
    VALUES  (@FileName,
             @VendorName
            )
END
-- Retrieve the automatically @ProcID VALUE from the Header table

SET @ProcessID = SCOPE_IDENTITY()

-- Insert new values into LabStagingDetails table
INSERT INTO LabStagingDetails 
            ([ProcessID],
            [LastName],
            [FirstName]     
            ) 
    VALUES (@ProcessID, 
            @LastName,
            @FirstName
            ) 
Run Code Online (Sandbox Code Playgroud)

问题是当 isFirstMSH 为 false 时,ProcessID 值为 NULL。如果 isFirstMSH 值为 false,则应在表中插入最后生成的值。

Aar*_*and 9

如果您多次调用该过程,则它们是不同的scopes,因此SCOPE_IDENTITY()预计为null. 并且您需要注意概念 - 如果您多次调用该过程,第二次调用如何真正确保“最后生成的值”来自该进程的前一次调用,而不是其他一些并发调用同样的程序?

考虑表值参数,以便您只需调用一次存储过程,如果此调用插入“第一”行并担心多个用户发生冲突,您可以停止跟踪:

CREATE TYPE dbo.TVPLabStagingDetails AS TABLE
(
   FirstName NVARCHAR(100),
   LastName  NVARCHAR(100)
);
Run Code Online (Sandbox Code Playgroud)

现在程序变成:

ALTER PROCEDURE dbo.[Insert_Header_Details_Tables]
    @FileName [varchar](50)    = null,
    @VendorName [varchar](250) = null,
    @Names dbo.TVPLabStagingDetails READONLY
AS
BEGIN
  SET NOCOUNT ON;

  INSERT dbo.LabStagingHeader([FileName], [VendorName]) 
    SELECT @FileName, @VendorName;

  DECLARE @ProcessID INT = SCOPE_IDENTITY();

  INSERT dbo.LabStagingDetails([ProcessID], [LastName], [FirstName])
    SELECT @ProcessID, LastName, FirstName FROM @Names;
END 
Run Code Online (Sandbox Code Playgroud)

如果这种改变是不可能的,就推迟;如果这也失败了,那么您将需要使用一个输出参数,以便客户端可以传入@ProcessID后续调用。但实际上,这是执行此操作的效率最低的方法。

其他一些花絮: