2009-10-27 14 views
31

Ho una tabella JET con un numero automatico come chiave primaria e vorrei sapere come posso recuperare questo numero dopo aver inserito una riga. Ho pensato di usare MAX() per recuperare la riga con il valore più alto, ma non sono sicuro di quanto sarebbe affidabile. Alcuni esempi di codice:Valore autonumber dell'ultima riga inserita - MS Access/VBA

Dim query As String 
Dim newRow As Integer 
query = "INSERT INTO InvoiceNumbers (date) VALUES (" & NOW() & ");" 
newRow = CurrentDb.Execute(query) 

Ora so che questo non avrebbe funzionato, dal momento che Execute() non restituirà il valore della chiave primaria, ma questo è fondamentalmente il tipo di codice che sto cercando. Dovrò utilizzare la chiave primaria della nuova riga per aggiornare un numero di righe in un'altra tabella.

Quale sarebbe il modo più semplice/più leggibile di farlo?

risposta

32

Se DAO utilizzare

RS.Move 0, RS.LastModified 
lngID = RS!AutoNumberFieldName 

Se ADO utilizzare

cn.Execute "INSERT INTO TheTable.....", , adCmdText + adExecuteNoRecords 
Set rs = cn.Execute("SELECT @@Identity", , adCmdText) 
Debug.Print rs.Fields(0).Value 

cn essere una connessione ADO valido, @@Identity restituirà l'ultimo Identity (Contatore) inserito su questa connessione.

Nota che @@Identity potrebbe essere problematico, perché l'ultimo valore generato non può essere quello che ti interessa. Per il motore di database di Access, si consideri un VIEW che unisce due tabelle, entrambi i quali hanno la proprietà IDENTITY, e si INSERT INTO lo VIEW. Per SQL Server, considerare se esistono trigger che a loro volta inseriscono record in un'altra tabella che ha anche la proprietà IDENTITY.

BTW DMax non funzionava come se qualcun altro inserisse un record subito dopo aver inserito un record ma prima che la funzione Dmax finisse l'escissione, si otterrebbe il loro record.

+14

DAO può fare SELECT @@ IDENTITY, anche - non hai bisogno di ADO. Lo faccio sempre: lngID = db.OpenRecordset ("SELECT @@ IDENTITY") (0), dove "db" è la stessa variabile di database utilizzata per eseguire l'inserimento. Non apro più recordset e Aggiungi per questo. –

41

Nell'esempio, poiché si utilizza CurrentDB per eseguire l'INSERT, è stato reso più difficile per te. Invece, questo funzionerà:

Dim query As String 
    Dim newRow As Long ' note change of data type 
    Dim db As DAO.Database 

    query = "INSERT INTO InvoiceNumbers (date) VALUES (" & NOW() & ");" 
    Set db = CurrentDB 
    db.Execute(query) 
    newRow = db.OpenRecordset("SELECT @@IDENTITY")(0) 
    Set db = Nothing 

ho usato per fare aggiunge aprendo un recordset AddOnly e raccogliendo l'ID da lì, ma questo è molto più efficiente. E, nota, Tony, che non richiede ADO.

+2

e funziona anche quando il recordset è una tabella collegata a SQL Server! Meraviglioso! –

+0

potresti anche aggiungere dbFailOnError come opzione per l'esecuzione. Altrimenti l'accesso non dirà nulla se fallisce. ----- db.Esegui query, dbFailOnError – JustJohn

+0

@iDevlop SQL Server supporta [la sintassi 'SELECT @@ IDENTITY'] (https://msdn.microsoft.com/en-us/library/ms187342.aspx). Sarebbe interessante vedere cosa succede in altri tipi di tabelle collegate come Excel o altri RDBMS come Oracle o MySQL. –

3

Questo è un adattamento dal mio codice per voi. Sono stato ispirato da developpez.com (Cerca nella pagina: "Pour insérer des données, vaut-il mieux passer par un RecordSet ou une requête de type INSERTO?"). Spiegano (con un po 'di francese). In questo modo è molto più veloce di quello superiore. Nell'esempio, questo modo era 37 volte più veloce. Provalo.

Const tableName As String = "InvoiceNumbers" 
Const columnIdName As String = "??" 
Const columnDateName As String = "date" 

Dim rsTable As DAO.recordSet 
Dim recordId as long 

Set rsTable = CurrentDb.OpenRecordset(tableName) 
Call rsTable .AddNew 
recordId = CLng(rsTable (columnIdName)) ' Save your Id in a variable 
rsTable (columnDateName) = Now()  ' Store your data 
rsTable .Update 

recordSet.Close 

LeCygne

+3

Potrebbe per favore identificare quale particolare esempio è "37 volte più veloce" di? –

1
Private Function addInsert(Media As String, pagesOut As Integer) As Long 


    Set rst = db.OpenRecordset("tblenccomponent") 
    With rst 
     .AddNew 
     !LeafletCode = LeafletCode 
     !LeafletName = LeafletName 
     !UNCPath = "somePath\" + LeafletCode + ".xml" 
     !Media = Media 
     !CustomerID = cboCustomerID.Column(0) 
     !PagesIn = PagesIn 
     !pagesOut = pagesOut 
     addInsert = CLng(rst!enclosureID) 'ID is passed back to calling routine 
     .Update 
    End With 
    rst.Close 

End Function 
+1

Non riesco a vedere come questo risponda alla domanda originale. Si prega di aggiungere contesto per vedere come questo si adatta? – GPI

+1

Questa risposta non è chiara. Per favore aggiungi spiegazioni. Non tutti noi sappiamo ** tutto ** su vba. – MJH

Problemi correlati