Jak uzyskać ostatnio wstawiony identyfikator?

174

Mam ten kod:

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

Kiedy wstawiam do tej tabeli, mam kolumnę klucza podstawowego auto_increment int o nazwie GamesProfileId, jak mogę uzyskać ostatnio wstawioną kolumnę po tym, aby móc użyć tego identyfikatora do wstawienia do innej tabeli?

anthonypliu
źródło

Odpowiedzi:

256

W przypadku SQL Server 2005+, jeśli nie ma wyzwalacza wstawiania, zmień instrukcję wstawiania (wszystkie w jednym wierszu, podzielone tutaj dla zachowania przejrzystości) na to

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

W przypadku programu SQL Server 2000 lub jeśli istnieje wyzwalacz wstawiania:

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

I wtedy

 Int32 newId = (Int32) myCommand.ExecuteScalar();
gbn
źródło
5
OUTPUT INSERTED.IDmoże generować problem w przypadku aktywnego wyzwalacza na stole
armen
2
Hmm. Kiedy próbowałem tego, pojawił się błąd: „Odwołanie do obiektu nie jest ustawione na wystąpienie obiektu”. mimo że jest uruchamiany natychmiast po wykonaniu polecenia Execute.
khany
@khany, naprawiłeś to?
TuGordoBello
5
„ID” w „OUTPUT INSERTED.ID” jest kluczem podstawowym. Myślałem, że to zastrzeżone słowo.
danmbuen
1
@VoidKing: Jak mam to ująć… robisz coś źle. Opublikuj nowe pytanie z przykładowym kodem, aby uzyskać pomoc. Oczywiście powiedziałeś mi, że się mylę, kiedy to po prostu działa dla wszystkich oprócz ciebie ...
gbn
38

Możesz utworzyć polecenie z CommandTextrównością

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

i wykonaj int id = (int)command.ExecuteScalar.

Ten artykuł MSDN zawiera dodatkowe techniki.

Jason
źródło
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();
}

Ta zła praca :)

Jeba Ra
źródło
vil? Myślę, że powinniśmy pisać bardziej poprawne gramatycznie odpowiedzi, aby być uczciwym
Zizzipupp
3

Miałem taką samą potrzebę i znalazłem tę odpowiedź.

Spowoduje to utworzenie rekordu w tabeli firmy (komp), pobranie automatycznego identyfikatora utworzonego na stole firmowym i umieszczenie go w tabeli personelu (personel), aby można było połączyć 2 tabele, WIELU pracowników do JEDNEJ firmy. Działa na mojej bazie danych SQL 2008, powinien działać na SQL 2005 i nowszych.

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

CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]

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

 @comp_regno nchar(8) = '12345678',

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

 @recID INT OUTPUT

- „ @recID” jest używany do przechowywania automatycznie wygenerowanego numeru identyfikacyjnego firmy, który zamierzamy pobrać

AS
 Begin

  SET NOCOUNT ON

  DECLARE @tableVar TABLE (tempID INT)

- Powyższy wiersz służy do tworzenia tabeli tymczasowej do przechowywania automatycznie generowanego numeru identyfikacyjnego do późniejszego wykorzystania. Ma tylko jedno pole „tempID”, a jego typ INT jest taki sam jak „@recID” .

  INSERT INTO comp(comp_name, comp_regno, comp_email) 

  OUTPUT inserted.comp_id INTO @tableVar

- WstawionoWYJŚCIE. 'powyżej jest używana do pobierania danych z dowolnego pola w rekordzie, który właśnie tworzy. Te potrzebne nam dane to autonumerowanie identyfikatora. Więc upewnij się, że zawiera poprawną nazwę pola dla twojej tabeli, moja to „comp_id” . To jest następnie upuszczane do tabeli tymczasowej, którą utworzyliśmy wcześniej.

  VALUES (@comp_name, @comp_regno, @comp_email)

  SET @recID = (SELECT tempID FROM @tableVar)

- Powyższa linia służy do przeszukiwania utworzonej wcześniej tabeli tymczasowej, w której zapisany jest potrzebny nam identyfikator. Ponieważ w tej tabeli tymczasowej jest tylko jeden rekord i tylko jedno pole, wybierze tylko potrzebny numer identyfikacyjny i upuści go w „ @recID ”. „ @recID ” ma teraz żądany numer identyfikacyjny i możesz go używać tak, jak chcesz, tak jak ja użyłem go poniżej.

  INSERT INTO staff(Staff_comp_id) 
  VALUES (@recID)

 End

- Więc proszę. Możesz faktycznie pobrać to, co chcesz, w wierszu „OUTPUT insert.WhatEverFieldNameYouWant” i utworzyć pola, które chcesz w tabeli tymczasowej, i uzyskać do nich dostęp, aby używać, jak chcesz.

Szukałem czegoś takiego od wieków, z tym szczegółowym podziałem, mam nadzieję, że to pomoże.

Sim2K
źródło
3

W czystym SQL główne instrukcje kools, takie jak:

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

Nawiasy kwadratowe definiują simbs tabeli, a następnie kolumny En i ID, nawiasy okrągłe określają wyliczenie kolumn, które mają zostać zainicjowane, a następnie wartości dla kolumn, w moim przypadku jedna kolumna i jedna wartość. Apostrofy zawierają ciąg

Wytłumaczę Ci moje podejście:

Może to nie być łatwe do zrozumienia, ale mam nadzieję, że przydatne będzie uzyskanie szerszego obrazu sytuacji przy użyciu ostatnio wstawionego identyfikatora. Oczywiście istnieją alternatywne, łatwiejsze podejścia. Ale mam powody, by zachować swoje. Funkcje skojarzone nie są uwzględniane, a jedynie ich nazwy i nazwy parametrów.

Używam tej metody do sztucznej inteligencji medycznej. Metoda sprawdza, czy poszukiwany ciąg istnieje w tabeli centralnej (1). Jeśli poszukiwany ciąg nie znajduje się w tabeli centralnej „simbs” lub jeśli dozwolone są duplikaty, to poszukiwany ciąg jest dodawany do tabeli centralnej „simbs” (2). Ostatni wpisany identyfikator jest używany do tworzenia powiązanej tabeli (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
źródło
2

Wypróbowałem powyższe, ale nie zadziałały, znalazłem tę myśl, która działa dobrze dla mnie.

var ContactID = db.GetLastInsertId();

Jest mniej kodu i łatwo go wprowadzić.

Mam nadzieję, że to komuś pomoże.

Matthew Mccall
źródło
1

Możesz również użyć wywołania SCOPE_IDENTITY w SQL Server.

Tim
źródło
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
źródło
1

Istnieje wiele sposobów uzyskania ostatniego wstawionego identyfikatora, ale najłatwiejszym sposobem, jaki znalazłem, jest po prostu pobranie go z TableAdapter w DataSet w następujący sposób:

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

Mam nadzieję że to pomoże ...

Andy Braham
źródło
0

Po wstawieniu dowolnego wiersza możesz uzyskać ostatnio wstawiony identyfikator, znajdując się poniżej linii zapytania.

INSERT INTO aspnet_GameProfiles (UserId, GameId) VALUES (@UserId, @GameId); WYBIERZ @@ TOŻSAMOŚĆ

RaviSoni-Systematix
źródło
-1

Użyj SELECT SCOPE_IDENTITY () w zapytaniu

Nimesh
źródło
-1

Po tym:

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

Wykonaj to

int id = (int)command.ExecuteScalar;

To będzie działać

M.Alaghemand
źródło
-2

INSERT INTO aspnet_GameProfiles (UserId, GameId) VALUES (@UserId, @GameId) "; wtedy możesz po prostu uzyskać dostęp do ostatniego identyfikatora, porządkując tabelę w sposób malejący.

SELECT TOP 1 UserId FROM aspnet_GameProfiles ORDER BY UserId DESC.

Aleks
źródło
Pod warunkiem, że ktoś nie użył IDENTITY_INSERT i dodał wiersz z dużo większym identyfikatorem użytkownika.
ldam
@Logan, rozumiem, to nie może działać tylko z charv jak id lub czymś mieszanym (charv + int), ale możesz ustawić kolumnę historyczną z przyrostowym int i załatwić to.
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
BICIE SERCA
źródło
To jest to, co uważam za naprawdę fajne ..... Teraz możesz pobrać ostatni zwiększony identyfikator z dowolnej tabeli w SQL -2005. W tym celu wystarczy wywołać tę procedurę z poziomu interfejsu. Zwróć uwagę, że passColumnName powinna mieć typ danych INT.
HEARTBEAT
2
Największym problemem tego podejścia w porównaniu z zaakceptowaną odpowiedzią jest to, że napotkasz problemy, jeśli wielu klientów będzie wstawiać dane w tym samym czasie. Jeśli jeden klient wykona dwa wywołania sql (pierwsze wstawienie, drugie ta procedura składowana), a pomiędzy tymi dwoma wywołaniami inny klient również wykona wstawianie, otrzymasz z powrotem zły identyfikator!
Oliver
4
To nie zwróci prawidłowego wyniku. Zwróci maksymalną wartość w kolumnie (która będzie zawierać wiersze wstawione przez innych użytkowników lub operacje), a nie ostatnią wstawioną przez Ciebie wartość. Dlatego działałoby to tylko w systemach dla jednego użytkownika. Użycie jednej z wbudowanych metod (np. Scope_identity ()) to jedyny poprawny sposób na uzyskanie ostatnio wstawionego identyfikatora w kontekście.
NickG