最後に挿入されたIDを取得する方法?


174

私はこのコードを持っています:

string insertSql = 
    "INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(@UserId, @GameId)";

using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
   myConnection.Open();

   SqlCommand myCommand = new SqlCommand(insertSql, myConnection);

   myCommand.Parameters.AddWithValue("@UserId", newUserId);
   myCommand.Parameters.AddWithValue("@GameId", newGameId);

   myCommand.ExecuteNonQuery();

   myConnection.Close();
}

このテーブルに挿入すると、auto_increment int主キー列と呼ばれGamesProfileIdますが、この後に最後に挿入されたものを取得して、そのIDを使用して別のテーブルに挿入するにはどうすればよいですか?

回答:


256

SQL Server 2005+の場合、挿入トリガーがない場合は、挿入ステートメント(ここでは明確にするためにすべて1行に分割)を次のように変更します。

INSERT INTO aspnet_GameProfiles(UserId,GameId)
OUTPUT INSERTED.ID
VALUES(@UserId, @GameId)

SQL Server 2000の場合、または挿入トリガーがある場合:

INSERT INTO aspnet_GameProfiles(UserId,GameId) 
VALUES(@UserId, @GameId);
SELECT SCOPE_IDENTITY()

その後

 Int32 newId = (Int32) myCommand.ExecuteScalar();

5
OUTPUT INSERTED.IDテーブルでアクティブなトリガーが発生した場合に問題が発生する可能性がある
armen

2
うーん。これを試したところ、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というエラーが発生しました。実行直後に実行されますが。
khany 2014年

@khany修正しましたか?
TuGordoBello 2014年

5
「OUTPUT INSERTED.ID」の「ID」が主キーです。予約語だと思いました。
danmbuen 2015年

1
@VoidKing:どうすればこれを置くことができますか。ヘルプのためにサンプルコードを使って新しい質問を投稿してください。明らかに、あなたを除いてすべての人に明白に機能するのは間違いだと言っていました...
gbn

38

次とCommandText等しいコマンドを作成できます

INSERT INTO aspnet_GameProfiles(UserId, GameId) OUTPUT INSERTED.ID VALUES(@UserId, @GameId)

そして、実行しint id = (int)command.ExecuteScalarます。

このMSDNの記事では、いくつかの追加のテクニックを紹介します。


6
string insertSql = 
    "INSERT INTO aspnet_GameProfiles(UserId,GameId) VALUES(@UserId, @GameId)SELECT SCOPE_IDENTITY()";

int primaryKey;

using (SqlConnection myConnection = new SqlConnection(myConnectionString))
{
   myConnection.Open();

   SqlCommand myCommand = new SqlCommand(insertSql, myConnection);

   myCommand.Parameters.AddWithValue("@UserId", newUserId);
   myCommand.Parameters.AddWithValue("@GameId", newGameId);

   primaryKey = Convert.ToInt32(myCommand.ExecuteScalar());

   myConnection.Close();
}

この邪悪な仕事:)


悪?文法的に正しい答えを正直に書く必要があると思います
Zizzipupp

3

私は同じ必要があり、この答えを見つけました..

これにより、companyテーブル(comp)にレコードが作成され、companyテーブルで作成された自動IDを取得して、それをStaffテーブル(staff)にドロップし、2つのテーブルをリンクできるようにします。SQL 2008 DBで動作しますが、SQL 2005以降で動作するはずです。

===========================

CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]

 @comp_name varchar(55) = 'Big Company',

 @comp_regno nchar(8) = '12345678',

 @comp_email nvarchar(50) = 'no1@home.com',

 @recID INT OUTPUT

-' @recID'は、取得しようとしている会社の自動生成ID番号を保持するために使用されます

AS
 Begin

  SET NOCOUNT ON

  DECLARE @tableVar TABLE (tempID INT)

-上記の行は、後で使用するために自動生成されたID番号を保持する一時テーブルを作成するために使用されます。それだけで一つのフィールド「tempID」を有し、そのタイプのINTが同じである「@recID」

  INSERT INTO comp(comp_name, comp_regno, comp_email) 

  OUTPUT inserted.comp_id INTO @tableVar

- ' OUTPUTを挿入します。上記の行は、現在作成中のレコードのフィールドからデータを取得するために使用されます。必要なこのデータはID自動番号です。テーブルの正しいフィールド名が表示されていることを確認してください。私のものは'comp_id'です。次に、これは前に作成した一時テーブルにドロップされます。

  VALUES (@comp_name, @comp_regno, @comp_email)

  SET @recID = (SELECT tempID FROM @tableVar)

-上記の行は、必要なIDが保存されている先に作成した一時テーブルを検索するために使用されます。この一時テーブルには1つのレコードと1つのフィールドしかないため、必要なID番号のみが選択され、 ' @recID 'にドロップされます。' @recID 'には、必要なID番号が付けられ、以下のように、好きなように使用できます。

  INSERT INTO staff(Staff_comp_id) 
  VALUES (@recID)

 End

-さあ、行きます。実際には、「挿入された OUTPUT.WhatEverFieldNameYouWant 行で必要なものを取得し、テンポラリーテーブルに必要なフィールドを作成し、それにアクセスして、必要な方法を使用できます。

私はこのようなものを長い間探していましたが、この詳細な内訳で、これが役立つことを願っています。


3

純粋なSQLでは、メインステートメントは次のようにクールになります。

INSERT INTO [simbs] ([En]) OUTPUT INSERTED.[ID] VALUES ('en')

角括弧はテーブルsimbsを定義し、次に列EnおよびIDを定義します。丸括弧は、開始する列の列挙を定義し、次に列の値を定義します。私の場合は1つの列と1つの値です。アポストロフィは文字列を囲みます

私のアプローチを説明します:

理解するのは簡単ではないかもしれませんが、最後に挿入されたIDを使用して全体像を把握するのに役立つと思います。もちろん、より簡単な代替方法があります。しかし、私には私を守る理由があります。関連する関数は含まれず、名前とパラメーター名のみが含まれます。

私はこの方法を医療用人工知能に使用しています。この方法では、目的の文字列が中央のテーブルに存在するかどうかを確認します(1)。必要な文字列が中央のテーブル「simbs」にない場合、または重複が許可されている場合、必要な文字列は中央のテーブル「simbs」に追加されます(2)。最後に挿入されたIDは、関連するテーブルを作成するために使用されます(3)。

    public List<int[]> CreateSymbolByName(string SymbolName, bool AcceptDuplicates)
    {
        if (! AcceptDuplicates)  // check if "AcceptDuplicates" flag is set
        {
            List<int[]> ExistentSymbols = GetSymbolsByName(SymbolName, 0, 10); // create a list of int arrays with existent records
            if (ExistentSymbols.Count > 0) return ExistentSymbols; //(1) return existent records because creation of duplicates is not allowed
        }
        List<int[]> ResultedSymbols = new List<int[]>();  // prepare a empty list
        int[] symbolPosition = { 0, 0, 0, 0 }; // prepare a neutral position for the new symbol
        try // If SQL will fail, the code will continue with catch statement
        {
            //DEFAULT und NULL sind nicht als explizite Identitätswerte zulässig
            string commandString = "INSERT INTO [simbs] ([En]) OUTPUT INSERTED.ID VALUES ('" + SymbolName + "') "; // Insert in table "simbs" on column "En" the value stored by variable "SymbolName"
            SqlCommand mySqlCommand = new SqlCommand(commandString, SqlServerConnection); // initialize the query environment
                SqlDataReader myReader = mySqlCommand.ExecuteReader(); // last inserted ID is recieved as any resultset on the first column of the first row
                int LastInsertedId = 0; // this value will be changed if insertion suceede
                while (myReader.Read()) // read from resultset
                {
                    if (myReader.GetInt32(0) > -1) 
                    {
                        int[] symbolID = new int[] { 0, 0, 0, 0 };
                        LastInsertedId = myReader.GetInt32(0); // (2) GET LAST INSERTED ID
                        symbolID[0] = LastInsertedId ; // Use of last inserted id
                        if (symbolID[0] != 0 || symbolID[1] != 0) // if last inserted id succeded
                        {
                            ResultedSymbols.Add(symbolID);
                        }
                    }
                }
                myReader.Close();
            if (SqlTrace) SQLView.Log(mySqlCommand.CommandText); // Log the text of the command
            if (LastInsertedId > 0) // if insertion of the new row in the table was successful
            {
                string commandString2 = "UPDATE [simbs] SET [IR] = [ID] WHERE [ID] = " + LastInsertedId + " ;"; // update the table by giving to another row the value of the last inserted id
                SqlCommand mySqlCommand2 = new SqlCommand(commandString2, SqlServerConnection); 
                mySqlCommand2.ExecuteNonQuery();
                symbolPosition[0] = LastInsertedId; // mark the position of the new inserted symbol
                ResultedSymbols.Add(symbolPosition); // add the new record to the results collection
            }
        }
        catch (SqlException retrieveSymbolIndexException) // this is executed only if there were errors in the try block
        {
            Console.WriteLine("Error: {0}", retrieveSymbolIndexException.ToString()); // user is informed about the error
        }

        CreateSymbolTable(LastInsertedId); //(3) // Create new table based on the last inserted id
        if (MyResultsTrace) SQLView.LogResult(LastInsertedId); // log the action
        return ResultedSymbols; // return the list containing this new record
    }

2

私は上記を試しましたが、うまくいきませんでした。私はこの考えを見つけました。

var ContactID = db.GetLastInsertId();

その少ないコードと私は入れやすい。

これが誰かを助けることを願っています。


1

SQL ServerでSCOPE_IDENTITYへの呼び出しを使用することもできます。


1
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;

namespace DBDemo2
{
    public partial class Form1 : Form
    {
        string connectionString = "Database=company;Uid=sa;Pwd=mypassword";
        System.Data.SqlClient.SqlConnection connection;
        System.Data.SqlClient.SqlCommand command;

        SqlParameter idparam = new SqlParameter("@eid", SqlDbType.Int, 0);
        SqlParameter nameparam = new SqlParameter("@name", SqlDbType.NChar, 20);
        SqlParameter addrparam = new SqlParameter("@addr", SqlDbType.NChar, 10);

        public Form1()
        {
            InitializeComponent();

            connection = new System.Data.SqlClient.SqlConnection(connectionString);
            connection.Open();
            command = new System.Data.SqlClient.SqlCommand(null, connection);
            command.CommandText = "insert into employee(ename, city) values(@name, @addr);select SCOPE_IDENTITY();";

            command.Parameters.Add(nameparam);
            command.Parameters.Add(addrparam);
            command.Prepare();

        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {


            try
            {
                int id = Int32.Parse(textBoxID.Text);
                String name = textBoxName.Text;
                String address = textBoxAddress.Text;

                command.Parameters[0].Value = name;
                command.Parameters[1].Value = address;

                SqlDataReader reader = command.ExecuteReader();
                if (reader.HasRows)
                {
                    reader.Read();
                    int nid = Convert.ToInt32(reader[0]);
                    MessageBox.Show("ID : " + nid);
                }
                /*int af = command.ExecuteNonQuery();
                MessageBox.Show(command.Parameters["ID"].Value.ToString());
                */
            }
            catch (NullReferenceException ne)
            {
                MessageBox.Show("Error is : " + ne.StackTrace);
            }
            catch (Exception ee)
            {
                MessageBox.Show("Error is : " + ee.StackTrace);
            }
        }

        private void buttonSave_Leave(object sender, EventArgs e)
        {

        }

        private void Form1_Leave(object sender, EventArgs e)
        {
            connection.Close();
        }
    }
}

1

Last Inserted IDを取得するにはさまざまな方法がありますが、私が見つけた最も簡単な方法は、次のようにDataSetのTableAdapterからIDを取得することです。

<Your DataTable Class> tblData = new <Your DataTable Class>();
<Your Table Adapter Class> tblAdpt = new <Your Table Adapter Class>();

/*** Initialize and update Table Data Here ***/

/*** Make sure to call the EndEdit() method ***/
/*** of any Binding Sources before update ***/
<YourBindingSource>.EndEdit();

//Update the Dataset
tblAdpt.Update(tblData);

//Get the New ID from the Table Adapter
long newID = tblAdpt.Adapter.InsertCommand.LastInsertedId;

お役に立てれば ...


0

行を挿入した後、クエリの行の下で最後に挿入されたIDを取得できます。

INSERT INTO aspnet_GameProfiles(UserId、GameId)VALUES(@UserId、@GameId); @@ IDENTITYを選択



-1

この後:

INSERT INTO aspnet_GameProfiles(UserId, GameId) OUTPUT INSERTED.ID VALUES(@UserId, @GameId)

これを実行

int id = (int)command.ExecuteScalar;

それが動作します


-2

INSERT INTO aspnet_GameProfiles(UserId、GameId)VALUES(@UserId、@GameId) ";次に、テーブルを下向きに並べ替えることで、最後のIDにアクセスできます。

aspnet_GameProfilesから上位1のユーザーIDを選択します。


誰かがIDENTITY_INSERTを使用しておらず、はるかに大きなUserIdを持つ行を追加した場合。
ldam

@Loganわかりました。IDのようなcharvや混合(charv + int)だけでは機能しませんが、incremental intを使用して履歴列を設定し、そのトリックを実行できます。
Aleks、2018年

-6
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[spCountNewLastIDAnyTableRows]
(
@PassedTableName as NVarchar(255),
@PassedColumnName as NVarchar(225)
)
AS
BEGIN
DECLARE @ActualTableName AS NVarchar(255)
DECLARE @ActualColumnName as NVarchar(225)
    SELECT @ActualTableName = QUOTENAME( TABLE_NAME )
    FROM INFORMATION_SCHEMA.TABLES
    WHERE TABLE_NAME = @PassedTableName
    SELECT @ActualColumnName = QUOTENAME( COLUMN_NAME )
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE COLUMN_NAME = @PassedColumnName
    DECLARE @sql AS NVARCHAR(MAX)
    SELECT @sql = 'select MAX('+ @ActualColumnName + ') + 1  as LASTID' + ' FROM ' + @ActualTableName 
    EXEC(@SQL)
END

これは私が本当に素晴らしいと思うものです..... SQL -2005の任意のテーブルから最後にインクリメントされたIDを取得できます。これには、フロントエンドからこのプロシージャを呼び出すだけです。passedColumnNameのデータ型はINTでなければならないことに注意してください。
HEARTBEAT

2
受け入れられた回答に対するこのアプローチの最大の問題は、複数のクライアントが同時にデータを挿入された場合に問題が発生することです。クライアント1が2つのSQL呼び出し(最初の挿入、2番目にこのストアドプロシージャ)を行い、それら2つの呼び出しの間に別のクライアントも挿入を行う場合、誤ったIDが返されます。
オリバー

4
これは正しい結果を返しません。これは、YOUが最後に挿入した値ではなく、列(他のユーザーまたは操作が挿入した行を含む)の最大値を返します。したがって、これはシングルユーザーシステムでのみ機能します。組み込みメソッドの1つ(たとえば、scope_identity())を使用することが、コンテキスト内で最後に挿入されたIDを取得する唯一の正しい方法です。
NickG 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.