¿Cómo obtener la última identificación insertada?

174

Tengo este codigo:

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

Cuando inserto en esta tabla, tengo una columna de clave primaria de auto_increment int llamada GamesProfileId, ¿cómo puedo obtener la última insertada después de esto para poder usar esa identificación para insertar en otra tabla?

anthonypliu
fuente

Respuestas:

256

Para SQL Server 2005+, si no hay un desencadenador de inserción, cambie la instrucción de inserción (toda una línea, dividida para mayor claridad aquí) a esto

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

Para SQL Server 2000, o si hay un desencadenador de inserción:

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

Y entonces

 Int32 newId = (Int32) myCommand.ExecuteScalar();
gbn
fuente
55
OUTPUT INSERTED.IDpodría generar un problema en caso de un activador activo en la mesa
armen
2
Hmm Cuando probé esto, recibí un error: "Referencia de objeto no establecida en una instancia de un objeto". a pesar de que se ejecuta inmediatamente después de la ejecución.
khany
@khany lo arreglaste?
TuGordoBello
55
la 'ID' en 'OUTPUT INSERTED.ID' es la clave principal por cierto. Pensé que era una palabra reservada.
danmbuen
1
@VoidKing: ¿Cómo puedo decir esto? Estás haciendo algo mal. Publique una nueva pregunta con código de muestra para obtener ayuda. Obviamente, usted me ha dicho que estoy equivocado cuando claramente funciona para todos, excepto que ...
GBN
38

Puede crear un comando con CommandTextigual a

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

y ejecutar int id = (int)command.ExecuteScalar.

Este artículo de MSDN le dará algunas técnicas adicionales.

jason
fuente
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 vil trabajo :)

Jeba Ra
fuente
vil? Creo que deberíamos escribir respuestas gramaticalmente más correctas para ser sincero
Zizzipupp
3

Tenía la misma necesidad y encontré esta respuesta ...

Esto crea un registro en la tabla de la compañía (comp), toma la identificación automática creada en la tabla de la compañía y la coloca en una tabla de Personal (staff) para que las 2 tablas puedan vincularse, MUCHOS empleados a UNA compañía. Funciona en mi base de datos SQL 2008, debería funcionar en SQL 2005 y superior.

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

CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]

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

 @comp_regno nchar(8) = '12345678',

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

 @recID INT OUTPUT

- El ' @recID' se usa para mantener el número de identificación generado automáticamente por la Compañía que estamos a punto de obtener

AS
 Begin

  SET NOCOUNT ON

  DECLARE @tableVar TABLE (tempID INT)

- La línea anterior se usa para crear una tabla temporal para contener el número de ID generado automáticamente para su uso posterior. Solo tiene un campo 'tempID' y su tipo INT es el mismo que '@recID' .

  INSERT INTO comp(comp_name, comp_regno, comp_email) 

  OUTPUT inserted.comp_id INTO @tableVar

-- Los ' SALIDA insertada. La línea anterior se utiliza para capturar datos de cualquier campo en el registro que está creando en este momento. Estos datos que queremos son el número de identificación automático. Así que asegúrese de que diga el nombre de campo correcto para su tabla, el mío es 'comp_id' . Esto se deja caer en la tabla temporal que creamos anteriormente.

  VALUES (@comp_name, @comp_regno, @comp_email)

  SET @recID = (SELECT tempID FROM @tableVar)

- La línea de arriba se usa para buscar en la tabla temporal que creamos anteriormente donde se guarda la ID que necesitamos. Como solo hay un registro en esta tabla temporal, y solo un campo, solo seleccionará el número de ID que necesita y lo colocará en ' colocará @recID '. ' @recID ' ahora tiene el número de identificación que deseas y puedes usarlo como quieras como lo he usado a continuación.

  INSERT INTO staff(Staff_comp_id) 
  VALUES (@recID)

 End

-- Ahí vas. En realidad, puedes tomar lo que quieras en el 'OUTPUT insertado. WhatEverFieldNameYouWant' y crear los campos que desee en su tabla temporal y acceder a ellos para usarlos como quiera.

Estuve buscando algo así por años, con este desglose detallado, espero que esto ayude.

Sim2K
fuente
3

En SQL puro, la declaración principal funciona como:

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

Los corchetes definen los símbolos de la tabla y luego las columnas En e ID, los corchetes definen la enumeración de las columnas que se iniciarán y luego los valores de las columnas, en mi caso, una columna y un valor. Los apóstrofos encierran una cadena

Te explicaré mi enfoque:

Puede que no sea fácil de entender, pero espero que sea útil para obtener una idea general utilizando la última identificación insertada. Por supuesto, hay enfoques alternativos más fáciles. Pero tengo razones para mantener la mía. Las funciones asociadas no están incluidas, solo sus nombres y nombres de parámetros.

Uso este método para la inteligencia artificial médica. El método verifica si la cadena deseada existe en la tabla central (1). Si la cadena deseada no está en la tabla central "simbs", o si se permiten duplicados, la cadena deseada se agrega a la tabla central "simbs" (2). La última identificación insertada se usa para crear la tabla asociada (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
fuente
2

Intenté lo anterior pero no funcionaron, encontré este pensamiento, eso funciona muy bien para mí.

var ContactID = db.GetLastInsertId();

Es menos código y fácil de poner.

Espero que esto ayude a alguien.

Matthew Mccall
fuente
1

También puede usar una llamada a SCOPE_IDENTITY en SQL Server.

Tim
fuente
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
fuente
1

Hay todo tipo de formas de obtener la última identificación insertada, pero la forma más fácil que he encontrado es simplemente recuperarla del TableAdapter en el DataSet de esta manera:

<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 esto ayude ...

Andy Braham
fuente
0

Después de insertar cualquier fila, puede obtener la última identificación insertada por debajo de la línea de consulta.

INSERTAR EN VALORES aspnet_GameProfiles (UserId, GameId) (@UserId, @GameId); SELECCIONAR @@ IDENTIDAD

RaviSoni-Systematix
fuente
-1

Use SELECT SCOPE_IDENTITY () en la consulta

Nimesh
fuente
-1

Después de este:

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

Ejecutar esto

int id = (int)command.ExecuteScalar;

Funcionará

M.Alaghemand
fuente
-2

INSERTAR EN aspnet_GameProfiles (UserId, GameId) VALUES (@UserId, @GameId) "; entonces puede acceder a la última identificación ordenando la tabla en la forma desc.

SELECCIONE EL ID DE USUARIO TOP 1 DESDE aspnet_GameProfiles ORDENAR POR UserId DESC.

Aleks
fuente
Siempre que alguien no haya usado IDENTITY_INSERT y haya agregado una fila con un UserId mucho más grande.
señora
@Logan, lo entiendo, no puede funcionar solo con un ID de charv o algo mezclado (charv + int), pero puede configurar una columna histórica con int incremental y hacer el truco.
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
LATIDO DEL CORAZÓN
fuente
Esto es lo que creo que es realmente agradable ... Ahora puede obtener la última identificación incrementada de cualquiera de las tablas en SQL -2005. Para esto solo necesita llamar a este procedimiento desde el front-end. Observe que pastColumnName debe tener el tipo de datos INT.
HEARTBEAT
2
El mayor problema de este enfoque contra la respuesta aceptada es que se encontrará con problemas si se insertan datos de varios clientes al mismo tiempo. Si el cliente uno hace dos llamadas sql (primer inserto, segundo este procedimiento almacenado) y entre esas dos llamadas otro cliente también hace un inserto, ¡obtendrá la identificación incorrecta!
Oliver
44
Esto no devolverá el resultado correcto. Devolverá el valor máximo en la columna (que incluirá filas que otros usuarios u operaciones han insertado), no el último valor que USTED insertó. Por lo tanto, esto solo funcionaría en sistemas de usuario único. El uso de uno de los métodos integrados (por ejemplo, scope_identity ()) es la única forma correcta de obtener la última ID insertada dentro del contexto.
NickG