web-dev-qa-db-ja.com

テーブルに最初の行を挿入した後、Scope_Identity()はnullを返します

2つのテーブルに値を挿入するために使用するストアドプロシージャがあります。

テーブルには親子関係があります。つまり、最初のテーブルにはID列があり、2番目のテーブルは最初のテーブルを参照します。

次の手順では、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
            ) 

問題は、isFirstMSHがfalseの場合、ProcessID値がNULLです。 isFirstMSH値がfalseの場合、最後に生成された値をテーブルに挿入する必要があります。

4
Vivek Kumar

プロシージャを複数回呼び出す場合、それらは異なるスコープなので、SCOPE_IDENTITY()nullであると想定されます。そして、概念に注意する必要があります-プロシージャを複数回呼び出す場合、2番目の呼び出しは、「最後に生成された値」がそのプロセスからの前の呼び出しからのものであるか、他のいくつかの同時呼び出しからのものであるかを確認します。同じ手順ですか?

テーブル値パラメーター を検討して、ストアドプロシージャを1回だけ呼び出す必要があるようにします。この呼び出しが「最初の」行を挿入し、複数のユーザーの衝突を心配している場合は追跡を停止できます。 :

_CREATE TYPE dbo.TVPLabStagingDetails AS TABLE
(
   FirstName NVARCHAR(100),
   LastName  NVARCHAR(100)
);
_

これで手順は次のようになります。

_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 
_

このような変更が不可能な場合は、差し戻します。それも失敗する場合は、クライアント側が後続の呼び出しで_@ProcessID_を渡すことができるように、出力パラメーターを使用する必要があります。しかし、実際には、これが最も効率の悪い方法です。

その他のヒント:

9
Aaron Bertrand

SCOPE_IDENTITY、IDENT_CURRENT、および@@ IDENTITYは、ID列に挿入される値を返すため、類似した関数です。テーブルにIDフィールドが定義されていない場合SCOPE_IDENTITYはNULLを返します

BEGIN TRANSACTION;
    CREATE TABLE dbo.sample (id          INT
                         PRIMARY KEY IDENTITY(1, 1), 
                         description VARCHAR(20)
                        );
    INSERT INTO dbo.sample
    (
        --id - column value is auto-generated
        description
    )
    VALUES
    (
        -- id - int
        'sample reg' -- description - varchar
    );
    SELECT SCOPE_IDENTITY(), 
           'return SCOPE_IDENTITY';
ROLLBACK TRANSACTION;
GO
BEGIN TRANSACTION;
    CREATE TABLE dbo.sample
                    (id          INT
                     PRIMARY KEY, 
                     description VARCHAR(20)
                    );
    INSERT INTO dbo.sample
    (id, -- column value is auto-generated 
     description
    )
    VALUES
    (20
     ,-- id - int 
     'sample reg' -- description - varchar
    );
    SELECT SCOPE_IDENTITY(), 
           'null return SCOPE_IDENTITY';
ROLLBACK TRANSACTION;