Como obter o último ID inserido?

174

Eu tenho este código:

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();
}

Quando insiro nesta tabela, tenho uma coluna de chave primária int auto_increment chamada GamesProfileId, como posso obter a última inserida depois disso para que eu possa usar esse ID para inserir em outra tabela?

anthonypliu
fonte

Respostas:

256

Para o SQL Server 2005+, se não houver gatilho de inserção, altere a instrução de inserção (toda uma linha, dividida para maior clareza aqui) para esta

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

Para o SQL Server 2000, ou se houver um gatilho de inserção:

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

E depois

 Int32 newId = (Int32) myCommand.ExecuteScalar();
gbn
fonte
5
OUTPUT INSERTED.IDpoderia gerar problema no caso de um gatilho ativo na mesa
armen
2
Hmm. Quando tentei isso, recebi um erro: "Referência de objeto não definida para uma instância de um objeto". mesmo que seja executado imediatamente após a execução.
Khany 17/05
@khany você consertou?
TuGordoBello
5
o 'ID' em 'OUTPUT INSERTED.ID' é a chave primária entre. Eu pensei que era uma palavra reservada.
danmbuen
1
@VoidKing: Como posso colocar isso ... você está fazendo algo errado. Poste uma nova pergunta com código de exemplo para obter ajuda. Obviamente, você me disse que eu estou errado quando se claramente funciona para todos, exceto você ...
GBN
38

Você pode criar um comando com CommandTextigual a

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

e executar int id = (int)command.ExecuteScalar.

Este artigo do MSDN fornecerá algumas técnicas adicionais.

Jason
fonte
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();
}

Este trabalho vil :)

Jeba Ra
fonte
vil? Acho que devemos escrever mais gramaticalmente respostas corretas para ser honesto
Zizzipupp
3

Eu tive a mesma necessidade e encontrei esta resposta ..

Isso cria um registro na tabela da empresa (comp), ele pega o ID automático criado na tabela da empresa e o solta em uma tabela da equipe (equipe) para que as duas tabelas possam ser vinculadas, MUITAS equipes a UMA empresa. Funciona no meu banco de dados SQL 2008, deve funcionar no SQL 2005 e acima.

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

CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]

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

 @comp_regno nchar(8) = '12345678',

 @comp_email nvarchar(50) = '[email protected]',

 @recID INT OUTPUT

- O ' @recID' é usado para armazenar o número de ID gerado automaticamente pela empresa que estamos prestes a obter

AS
 Begin

  SET NOCOUNT ON

  DECLARE @tableVar TABLE (tempID INT)

- A linha acima é usada para criar uma tabela temporária para armazenar o número de ID gerado automaticamente para uso posterior. Ele possui apenas um campo 'tempID' e seu tipo INT é igual ao '@recID' .

  INSERT INTO comp(comp_name, comp_regno, comp_email) 

  OUTPUT inserted.comp_id INTO @tableVar

- A ' SAÍDA inserida. A linha acima é usada para capturar dados de qualquer campo no registro que está criando no momento. Esses dados que queremos é o número automático de ID. Portanto, verifique se ele diz o nome do campo correto para sua tabela, a minha é 'comp_id' . Isso é descartado na tabela temporária que criamos anteriormente.

  VALUES (@comp_name, @comp_regno, @comp_email)

  SET @recID = (SELECT tempID FROM @tableVar)

- A linha acima é usada para pesquisar a tabela temporária que criamos anteriormente, onde o ID que precisamos é salvo. Como existe apenas um registro nessa tabela temporária e apenas um campo, ele selecionará apenas o número de identificação necessário e o soltará em ' @recID '. ' @recID ' agora tem o número de identificação desejado e você pode usá-lo como quiser, como eu o usei abaixo.

  INSERT INTO staff(Staff_comp_id) 
  VALUES (@recID)

 End

- Então lá vai você. Você pode realmente pegar o que quiser na linha 'OUTPUT inserida. WhatEverFieldNameYouWant ' e criar os campos que deseja na sua tabela temporária e acessá-lo para usar como quiser.

Eu estava procurando por algo assim há muito tempo, com essa quebra detalhada, espero que isso ajude.

Sim2K
fonte
3

No SQL puro, a instrução principal é semelhante a:

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

Os colchetes definem os simbs da tabela e, em seguida, as colunas En e ID, entre colchetes definem a enumeração das colunas a serem iniciadas e os valores das colunas, no meu caso, uma coluna e um valor. Os apóstrofos incluem uma string

Vou explicar minha abordagem:

Pode não ser fácil de entender, mas espero que seja útil obter uma imagem geral usando o último ID inserido. Claro que existem abordagens alternativas mais fáceis. Mas tenho razões para manter a minha. As funções associadas não são incluídas, apenas seus nomes e nomes de parâmetros.

Eu uso esse método para inteligência artificial médica. O método verifica se a sequência desejada existe na tabela central (1). Se a sequência desejada não estiver na tabela central "simbs" ou se duplicatas forem permitidas, a sequência desejada será adicionada à tabela central "simbs" (2). O último id inseertado é usado para criar a tabela associada (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
    }
profimedica
fonte
2

Eu tentei o acima, mas eles não funcionaram, achei esse pensamento, que funciona muito bem para mim.

var ContactID = db.GetLastInsertId();

É menos código e fácil de inserir.

Espero que isso ajude alguém.

Matthew Mccall
fonte
1

Você também pode usar uma chamada para SCOPE_IDENTITY no SQL Server.

Tim
fonte
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();
        }
    }
}
pgp
fonte
1

Existem várias maneiras de obter o último ID inserido, mas a maneira mais fácil que encontrei é simplesmente recuperá-lo do TableAdapter no DataSet da seguinte maneira:

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

Espero que isto ajude ...

Andy Braham
fonte
0

Depois de inserir qualquer linha, você pode obter o último ID inserido abaixo da linha de consulta.

INSERIR EM aspnet_GameProfiles (UserId, GameId) VALUES (@UserId, @GameId); SELECT @@ IDENTITY

RaviSoni-Systematix
fonte
-1

Use SELECT SCOPE_IDENTITY () na consulta

Nimesh
fonte
-1

Depois disto:

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

Execute isso

int id = (int)command.ExecuteScalar;

Vai funcionar

M.Alaghemand
fonte
-2

INSERT IN aspnet_GameProfiles (UserId, GameId) VALUES (@UserId, @GameId) "; então você pode acessar o último ID ordenando a tabela da maneira desc.

SELECIONE O TOP 1 ID do Usuário DE aspnet_GameProfiles ORDER BY UserId DESC.

Aleks
fonte
Desde que alguém não tenha usado IDENTITY_INSERT e adicionado uma linha com um UserId muito maior.
ldam
@Logan eu entendo, não pode funcionar apenas com um charv como id ou algo misto (charv + int), mas você pode configurar uma coluna histórica com int incremental e fazer o truque.
Aleks
-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
BATIMENTO CARDIACO
fonte
Isto é o que eu acho realmente bom ... Agora você pode obter o último ID incrementado de qualquer tabela da SQL -2005. Para isso, você só precisa chamar esse procedimento do front end. Observe que o passouColumnName deve ter o tipo de dados INT.
HEARTBEAT
2
O maior problema dessa abordagem em relação à resposta aceita é que você terá problemas se vários clientes inserirem dados ao mesmo tempo. Se o cliente um fizer duas chamadas sql (primeira inserção, depois este procedimento armazenado) e entre essas duas chamadas outro cliente também fizer uma inserção, você receberá o ID errado de volta!
Oliver
4
Isso não retornará o resultado correto. Ele retornará o valor máximo na coluna (que incluirá linhas que outros usuários ou operações inseriram) e não o último valor que você inseriu. Portanto, isso funcionaria apenas em sistemas de usuário único. Usar um dos métodos internos (por exemplo, scope_identity ()) é a única maneira correta de obter o último ID inserido dentro do contexto.
NickG