0

次の ID を取得するためにクエリを実行しますか? これは、削除されたレコードのないテーブルで可能です。

SELECT TOP 1 EMPID + 1 FROM Employee ORDER BY EMPID DESC

削除されたデータがある場合、次の ID を取得するにはどうすればよいですか? たとえば、次のようなテーブルがあります。

EMPID    NAME
4001     someName
4002     someName
4003 ----------------------- this is deleted
4004     someName
4005     someName
4006     someName
4007     someName
4008     someName
4009 ----------------------- this is deleted
4010 ----------------------- this is deleted

出力は 4011 でなければなりません

4

2 に答える 2

11

IDENTITYアプリケーションのフォームに確実に値を表示する唯一の方法は、 INSERT IT FIRSTです。IDENT_CURRENTあなたがそれをテストしている唯一の人であれば、あなたを助けるように見えるかもしれませんが、複数のユーザーがあなたのアプリケーションを使用すると、これはすぐに崩壊するでしょう. 証明するのもとても簡単です。次のテーブルを作成します。

CREATE TABLE dbo.whatever(ID INT IDENTITY(1,1), blat CHAR(1));

ここで、2 つの別々の Management Studio ウィンドウで、最初に次のコードを実行します。このコードは、受け入れられた回答に従い、「機能する」と言った場合に、フォームに表示される内容をシミュレートします。

SELECT IDENT_CURRENT('dbo.whatever');

出力に注意してください (両方とも である必要があります1)。正解です。これまでのところ

ここで、1 つのウィンドウで次のコマンドを実行します。

INSERT dbo.whatever(blat) SELECT 'x';
SELECT SCOPE_IDENTITY();

出力は次のようになります1(これも正しいSO FARです)。

次に、別のウィンドウで同じことを実行しますが、に変更xyます。この出力は現在2. うーん。これは、フォームでこのユーザーに表示したものと一致しません。1テーブルにと2IDENTITY値を持つ 2 つの行があることを確認することで、それを検証することもできます。

SELECT ID, blat FROM dbo.whatever;

これを行う正しい方法と唯一の方法は、行を挿入し、値を取得して、フォームに表示することです事前にサロゲート値を表示する必要がある場合 (なぜこれを行う必要があるのか​​、またはいつ取得してもエンド ユーザーがこの値を知る必要があるのか​​ わかりません。なぜユーザーは ID が何であるかを気にするのでしょうか?)別のテーブルを作成し、IDENTITYそこに値を生成します。

CREATE TABLE dbo.dummy_table(ID INT IDENTITY(1,1) PRIMARY KEY);
GO
CREATE TABLE dbo.real_table(ID INT PRIMARY KEY, ...other columns...);
GO

フォームに「次の」ID を表示したい場合は、次のようにします。

INSERT dbo.dummy_table DEFAULT VALUES;
SELECT SCOPE_IDENTITY();

次に、ユーザーが残りの情報を入力すると、から取得した値を使用して、挿入リストに列を挿入しdbo.real_tableて含めることができます。ユーザーが ID を見て [保存] をクリックしなかった場合、これでもギャップが生じることに注意してください。ただし、その ID は実際のテーブルには含まれていないため、意味がありません。それを見たことがあります( 、および他の考えられていない「最初に値をチェックする」手法で起こりうることとは異なります)。IDdbo.dummy_tableIDENT_CURRENTMAX+1

実際の目標が本を 3 部別のテーブルに挿入することである場合、解決策は非常に簡単ですが、最初に本を挿入する必要があります。本の名前と部数を表すパラメータがあると仮定しましょう (他のパラメータも同様です):

DECLARE @Copies INT, @name NVARCHAR(32);

SELECT @Copies = 3, @name = N'Moby Dick';

これで、テーブルに挿入しdbo.Books、出力を使用して複数の行を他のテーブルに挿入できます ( dbo.Accession?)。firstの「次の」値をやみくもに推測する必要はありませんBookID

DECLARE @BookID INT;

INSERT dbo.Books(name, copies, whatever...) SELECT N'Moby Dick', 3, ...;

SELECT @BookID = SCOPE_IDENTITY();

INSERT dbo.Accession(AccessionID, BookID)
  SELECT rn, @BookID
  FROM
  (
    SELECT TOP (@Copies) rn = ROW_NUMBER() OVER (ORDER BY [object_id])
    FROM sys.columns ORDER BY [object_id]
  ) AS y;

これは、カタログ ビューから複数の行を生成するトリックを使用しますが、組み込みのNumbersテーブルがある場合は、それを使用して効率を向上させる (および権限の制限を緩和する) こともできます。

于 2013-08-12T18:50:57.860 に答える
1

SQL SERVERをご覧ください– @@IDENTITY vs SCOPE_IDENTITY() vs IDENT_CURRENT – レコードの最後に挿入された ID を取得する

以下に示すように、違いに注意してください。

IDENT_CURRENT の使用を検討することをお勧めします。

IDENT_CURRENT (Transact-SQL)

指定されたテーブルまたはビューに対して生成された最後の ID 値を返します。生成された最後の ID 値は、任意のセッションおよび任意のスコープに対して使用できます。

SCOPE_IDENTITY (Transact-SQL)

同じスコープ内の ID 列に最後に挿入された ID 値を返します。スコープは、モジュール (ストアド プロシージャ、トリガー、関数、またはバッチ) です。したがって、2 つのステートメントが同じストアド プロシージャ、関数、またはバッチ内にある場合、これらのステートメントは同じスコープ内にあります。

@@IDENTITY (Transact-SQL)

INSERT、SELECT INTO、または一括コピー ステートメントが完了すると、@@IDENTITY には、ステートメントによって生成された最後の ID 値が含まれます。ステートメントが ID 列を持つテーブルに影響を与えなかった場合、@@IDENTITY は NULL を返します。複数の行が挿入され、複数の ID 値が生成される場合、@@IDENTITY は最後に生成された ID 値を返します。ID 値を生成する挿入を実行する 1 つ以上のトリガーをステートメントが起動する場合、ステートメントの直後に @@IDENTITY を呼び出すと、トリガーによって生成された最後の ID 値が返されます。ID 列を持つテーブルに対する挿入アクションの後にトリガーが起動され、そのトリガーが ID 列を持たない別のテーブルに挿入される場合、@@IDENTITY は最初の挿入の ID 値を返します。

于 2013-08-12T18:25:30.877 に答える