Comment obtenir le dernier identifiant inséré?

174

J'ai ce code:

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

Lorsque j'insère dans cette table, j'ai une colonne de clé primaire auto_increment int appelée GamesProfileId, comment puis-je obtenir la dernière insérée après cela afin que je puisse utiliser cet identifiant pour l'insérer dans une autre table?

anthonypliu
la source

Réponses:

256

Pour SQL Server 2005+, s'il n'y a pas de déclencheur d'insertion, modifiez l'instruction d'insertion (toute une ligne, divisée ici pour plus de clarté)

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

Pour SQL Server 2000 ou s'il existe un déclencheur d'insertion:

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

Puis

 Int32 newId = (Int32) myCommand.ExecuteScalar();
gbn
la source
5
OUTPUT INSERTED.IDpourrait générer un problème en cas de déclenchement actif sur la table
armen
2
Hmm. Quand j'ai essayé cela, j'ai eu une erreur: "La référence d'objet n'est pas définie sur une instance d'un objet." même s'il est exécuté immédiatement après l'Execute.
khany
@khany l'avez-vous résolu?
TuGordoBello
5
«ID» dans «OUTPUT INSERTED.ID» est la clé primaire btw. Je pensais que c'était un mot réservé.
danmbuen
1
@VoidKing: Comment est-ce que je peux dire ça ... vous faites quelque chose de mal. Postez une nouvelle question avec un exemple de code pour obtenir de l'aide. De toute évidence, vous m'avez dit que je me trompais quand cela fonctionne clairement pour tout le monde sauf vous ...
gbn
38

Vous pouvez créer une commande CommandTextégale à

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

et exécutez int id = (int)command.ExecuteScalar.

Cet article MSDN vous donnera quelques techniques supplémentaires.

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

Ce vil travail :)

Jeba Ra
la source
vil? Je pense que nous devrions écrire des réponses plus grammaticalement correctes pour être honnête
Zizzipupp
3

J'avais le même besoin et j'ai trouvé cette réponse.

Cela crée un enregistrement dans la table d'entreprise (comp), il récupère l'ID automatique créé sur la table d'entreprise et le dépose dans une table Staff (staff) afin que les 2 tables puissent être liées, BEAUCOUP d'employés à UNE entreprise. Cela fonctionne sur ma base de données SQL 2008, devrait fonctionner sur SQL 2005 et au-dessus.

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

CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]

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

 @comp_regno nchar(8) = '12345678',

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

 @recID INT OUTPUT

- Le ' @recID' est utilisé pour contenir le numéro d'identification généré automatiquement par l'entreprise que nous sommes sur le point de saisir

AS
 Begin

  SET NOCOUNT ON

  DECLARE @tableVar TABLE (tempID INT)

- La ligne ci-dessus est utilisée pour créer une table temporaire contenant le numéro d'identification généré automatiquement pour une utilisation ultérieure. Il n'a qu'un seul champ 'tempID' et son type INT est le même que '@recID' .

  INSERT INTO comp(comp_name, comp_regno, comp_email) 

  OUTPUT inserted.comp_id INTO @tableVar

- Le ' OUTPUT inséré. La ligne ci-dessus est utilisée pour extraire des données de n'importe quel champ de l'enregistrement qu'il crée en ce moment. Ces données que nous voulons sont la numérotation automatique ID. Assurez-vous donc qu'il indique le nom de champ correct pour votre table, le mien est 'comp_id' . Ceci est ensuite déposé dans la table temporaire que nous avons créée précédemment.

  VALUES (@comp_name, @comp_regno, @comp_email)

  SET @recID = (SELECT tempID FROM @tableVar)

- La ligne ci-dessus est utilisée pour rechercher la table temporaire que nous avons créée précédemment où l'ID dont nous avons besoin est enregistré. Puisqu'il n'y a qu'un seul enregistrement dans cette table temporaire, et un seul champ, il ne sélectionnera que le numéro d'identification dont vous avez besoin et le déposera dans ' @recID '. ' @recID ' a maintenant le numéro d'identification que vous voulez et vous pouvez l'utiliser comme vous le souhaitez, comme je l'ai utilisé ci-dessous.

  INSERT INTO staff(Staff_comp_id) 
  VALUES (@recID)

 End

- Alors voilà. Vous pouvez en fait saisir ce que vous voulez dans la ligne 'OUTPUT INSERT.WhatEverFieldNameYouWant' et créer les champs que vous voulez dans votre table temporaire et y accéder pour l'utiliser comme vous le souhaitez.

Je cherchais quelque chose comme ça depuis des lustres, avec cette ventilation détaillée, j'espère que cela aide.

Sim2K
la source
3

En SQL pur, l'instruction principale fonctionne comme:

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

Les crochets définissent le tableau simbs puis les colonnes En et ID, les crochets ronds définissent l'énumération des colonnes à lancer puis les valeurs des colonnes, dans mon cas une colonne et une valeur. Les apostrophes entourent une chaîne

Je vais vous expliquer ma démarche:

Ce n'est peut-être pas facile à comprendre, mais j'espère qu'il sera utile d'avoir une vue d'ensemble en utilisant le dernier identifiant inséré. Bien entendu, il existe des approches alternatives plus simples. Mais j'ai des raisons de garder les miennes. Les fonctions associées ne sont pas incluses, mais uniquement leurs noms et noms de paramètres.

J'utilise cette méthode pour l'intelligence artificielle médicale La méthode vérifie si la chaîne voulue existe dans la table centrale (1). Si la chaîne souhaitée n'est pas dans la table centrale "simbs", ou si les doublons sont autorisés, la chaîne souhaitée est ajoutée à la table centrale "simbs" (2). Le dernier identifiant inséré est utilisé pour créer la table associée (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
la source
2

J'ai essayé ce qui précède mais cela n'a pas fonctionné, j'ai trouvé cette pensée, qui fonctionne très bien pour moi.

var ContactID = db.GetLastInsertId();

C'est moins de code et c'est facile à mettre.

J'espère que cela aide quelqu'un.

Matthew Mccall
la source
1

Vous pouvez également utiliser un appel à SCOPE_IDENTITY dans SQL Server.

Tim
la source
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
la source
1

Il existe toutes sortes de façons d'obtenir le dernier ID inséré, mais le moyen le plus simple que j'ai trouvé consiste simplement à le récupérer à partir du TableAdapter dans le DataSet comme suit:

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

J'espère que cela t'aides ...

Andy Braham
la source
0

Après avoir inséré une ligne, vous pouvez obtenir le dernier identifiant inséré sous la ligne de requête.

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

RaviSoni-Systematix
la source
-1

Utilisez SELECT SCOPE_IDENTITY () dans la requête

Nimesh
la source
-1

Après ça:

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

Exécutez ceci

int id = (int)command.ExecuteScalar;

Ça va marcher

M. Alaghemand
la source
-2

INSERT INTO aspnet_GameProfiles (UserId, GameId) VALUES (@UserId, @GameId) "; alors vous pouvez simplement accéder au dernier identifiant en ordonnant la table de manière desc.

SELECT TOP 1 UserId FROM aspnet_GameProfiles ORDER BY UserId DESC.

Aleks
la source
À condition que quelqu'un n'ait pas utilisé IDENTITY_INSERT et ajouté une ligne avec un UserId beaucoup plus grand.
ldam
@Logan je comprends, cela ne peut pas fonctionner avec juste un charv comme id ou quelque chose de mixte (charv + int) mais vous pouvez configurer une colonne historique avec incrémental int et faire l'affaire.
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
BATTEMENT DE COEUR
la source
C'est ce que je pense être vraiment sympa ..... Maintenant, vous pouvez obtenir le dernier identifiant incrémenté de n'importe quelle table dans SQL -2005. Pour cela, il vous suffit d'appeler cette procédure depuis le front-end. Notez que le PassColumnName doit avoir le type de données INT.
HEARTBEAT
2
Le plus gros problème de cette approche par rapport à la réponse acceptée est que vous rencontrerez des problèmes si plusieurs clients sont insérés des données en même temps. Si le client un fait deux appels SQL (premier insert, deuxième cette procédure stockée) et entre ces deux appels un autre client fait également une insertion, vous obtiendrez le mauvais ID!
Oliver
4
Cela ne renverra pas le résultat correct. Il renverra la valeur maximale dans la colonne (qui comprendra les lignes que d'autres utilisateurs ou opérations ont insérées) et non la dernière valeur que VOUS avez insérée. Par conséquent, cela ne fonctionnerait que sur les systèmes mono-utilisateur. Utiliser l'une des méthodes intégrées (par exemple scope_identity ()) est la seule manière correcte d'obtenir le dernier ID inséré dans le contexte.
NickG