2009-07-14 36 views
6

È possibile restituire l'ultima riga di una tabella in MS SQL Server. Sto usando un campo di incremento automatico per l'ID e voglio ottenere l'ultimo appena aggiunto per unirlo con qualcos'altro. Qualche idea?Selezionare l'ultima riga in una tabella SQL

Ecco il codice:

const string QUERY = @"INSERT INTO Questions (ID, Question, Answer, CategoryID, Permission) " 
        + @"VALUES (@ID, @Question, @Answer, @CategoryID, @Permission) "; 

using (var cmd = new SqlCommand(QUERY, conn)) 
{ 
    cmd.Parameters.AddWithValue("@Question", question); 
    cmd.Parameters.AddWithValue("@Answer", answer); 
    cmd.Parameters.AddWithValue("@CategoryID", lastEdited); 
    cmd.Parameters.AddWithValue("@Permission", categoryID); 
    cmd.ExecuteNonQuery(); 
} 

risposta

19

usando un campo di incremento automatico ... e voglio ottenere l'ultimo appena aggiunto ad unirsi con qualcos'altro.

La chiave qui è "appena aggiunto". Se hai un sacco di utenti diversi che colpiscono il db allo stesso tempo, non penso che tu voglia che l'utente A recuperi il record creato dall'utente B. Ciò significa che probabilmente vorrai utilizzare la funzione scope_identity() per ottenere quell'id anziché eseguire nuovamente una query sul tavolo immediatamente.

A seconda del contesto, potrebbe anche essere necessario @@identity (includere i trigger) o ident_current('questions') (limitato a una tabella specifica, ma non all'ambito specifico). Ma scope_identity() è quasi sempre quello giusto da usare.


Ecco un esempio:

DECLARE @NewOrderID int 

INSERT INTO TABLE [Orders] (CustomerID) VALUES (1234) 

SELECT @NewOrderID=scope_identity() 

INSERT INTO TABLE [OrderLines] (OrderID, ProductID, Quantity) 
    SELECT @NewOrderID, ProductID, Quantity 
    FROM [ShoppingCart] 
    WHERE CustomerID=1234 AND SessionKey=4321 

In base al codice che hai postato, si può fare qualcosa di simile:

// don't list the ID column: it should be an identity column that sql server will handle for you 
const string QUERY = "INSERT INTO Questions (Question, Answer, CategoryID, Permission) " 
        + "VALUES (@Question, @Answer, @CategoryID, @Permission);" 
        + "SELECT scope_identity();"; 

int NewQuestionID; 
using (var cmd = new SqlCommand(QUERY, conn)) 
{ 
    cmd.Parameters.AddWithValue("@Question", question); 
    cmd.Parameters.AddWithValue("@Answer", answer); 
    cmd.Parameters.AddWithValue("@CategoryID", lastEdited); 
    cmd.Parameters.AddWithValue("@Permission", categoryID); 
    NewQuestionID = (int)cmd.ExecuteScalar(); 
} 

Vedere la mia risposta ad un'altra domanda qui:
get new SQL record ID

Il problema ora è che probabilmente vorrai che le successive istruzioni sql si trovino nella stessa transazione. Si potrebbe fare questo con il codice client, ma trovo che mantenere tutto sul server sia più pulito. È possibile farlo creando una stringa sql molto lunga, ma a questo punto preferisco una stored procedure.

Non sono un fan del metodo .AddWithValue() — Preferisco definire esplicitamente i tipi di parametro — ma possiamo lasciarlo per un altro giorno.

Infine, è un po 'tardi ora, ma voglio sottolineare che è davvero meglio provare a mantenere tutto questo sul db. È possibile eseguire più istruzioni in un comando sql e si desidera ridurre il numero di round trip necessari al db e la quantità di dati necessari per passare avanti e indietro tra il db e l'app. Rende anche più facile ottenere le transazioni giuste e mantenere le cose atomiche dove devono essere.

+1

+1 per menzionare scope_identity() è quasi sempre quello giusto da usare. – RichardOD

+0

ho sorpreso nessuno menzionato identity_current, ho postato alcuni collegamenti ed esempi –

+0

ma l'identità dell'ambito mi riporta indietro una colonna di valori nulli voglio l'ultimo non il conteggio? appena aggiunto: le precedenti linee di codici sono stati quelli che hanno aggiunto questo nuova riga –

4
select top 1 * from yourtable order by id desc 
+0

Fare attenzione. Questo sembra a prima vista, ma se leggi la domanda da vicino ci sono dei problemi. –

+1

Vero, ma la domanda non è del tutto chiara. "unirsi a" potrebbe anche significare trovare record correlati all'ultimo nella tabella. –

+0

-1 questo restituirà l'ultimo inserimento da parte di qualsiasi utente, non l'ultimo utente dell'utente corrente –

10

uso

  • SCOPE_IDENTITY() restituisce l'ultimo valore Identity generato in questa sessione e questo ambito
  • IDENT_CURRENT() restituisce l'ultimo valore dell'identità e generato per una particolare tabella in ogni sessione e qualsiasi ambito

    selezionare IDENT_CURRENT ('yourTableName')

restituirà l'ultima identità per una sessione diversa.

La maggior parte delle volte è necessario utilizzare scope_identity() subito dopo un'istruzione di inserimento in questo modo.

--insert statement 
SET @id = CAST(SCOPE_IDENTITY() AS INT) 
+0

......... booo :( –

+0

Stan non ho fatto downvote- ma è corretto cancellare le risposte! – RichardOD

+1

basta modificare la risposta per interrompere suggerimento: nessuno ha effettivamente fornito il tsql per usare scope_identity(). – dotjoe

24

Non sicuro - potrebbe avere più inserti in corso, allo stesso tempo e l'ultima riga si otterrebbe potrebbe non essere la vostra. Stai meglio usando SCOPE_IDENTITY() per ottenere l'ultima chiave assegnata per la tua transazione.

+1

Punto eccellente. Quando ho postato ho appena letto "dammi l'ultima riga". Ho ignorato la sua intenzione di usarlo per creare un riferimento di chiave esterna. – Randolpho

+0

+1 per fornire la soluzione corretta – dotjoe

+0

+1: corretto se il client non avvia una nuova transazione. –

-1

Con un semplice selezionare si può fare qualcosa di simile:

SELECT * 
FROM table_name 
WHERE IDColumn=(SELECT max(IDColum) FROM table_name) 
+0

non sicuro in un ambiente concorrente ...... –

1

Non sono sicuro della versione di SQL Server, ma cerca la clausola OUTPUT dell'istruzione INSERT. È possibile acquisire una serie di righe con questa clausola

1

Poiché l'interrogante utilizza .NET, ecco un esempio modificato di come farlo. (Ho tolto ID dalla lista inserto dal momento che è auto-incremento - l'esempio originale non riuscirebbe ho anche assumere ID è un int SQL, non un bigint..)

 const string QUERY = @"INSERT INTO Questions (Question, Answer, CategoryID, Permission) " 
          + @"VALUES (@Question, @Answer, @CategoryID, @Permission);" 
          + @"SELECT @ID = SCOPE_IDENTITY();"; 

     using (var cmd = new SqlCommand(QUERY, conn)) 
     { 
      cmd.Parameters.AddWithValue("@Question", question); 
      cmd.Parameters.AddWithValue("@Answer", answer); 
      cmd.Parameters.AddWithValue("@CategoryID", lastEdited); 
      cmd.Parameters.AddWithValue("@Permission", categoryID); 
      cmd.Parameters.Add("@ID", System.Data.SqlDbType.Int).Direction = ParameterDirection.Output; 
      cmd.ExecuteNonQuery(); 

      int id = (int)cmd.Parameters["@ID"].Value; 
     } 

Modificato: Propongo inoltre considerare LINQ to SQL invece di oggetti SqlCommand con codifica manuale: è molto meglio (più veloce da codificare, più facile da usare) per molti scenari comuni.

Problemi correlati