2009-10-27 22 views
31

Tengo una tabla JET con un número automático como clave principal, y me gustaría saber cómo puedo recuperar este número después de insertar una fila. He pensado en usar MAX() para recuperar la fila con el valor más alto, pero no estoy seguro de cuán confiable sería. Un código de ejemplo:Autonumérico valor de la última fila insertada - MS Access/VBA

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

Ahora sé que esto no funcionaría, ya que Execute() no devolverá el valor de la clave primaria, pero esto es básicamente el tipo de código que estoy buscando. Necesitaré usar la clave primaria de la nueva fila para actualizar varias filas en otra tabla.

¿Cuál sería la forma más simple/más legible de hacer esto?

Respuesta

32

Si DAO utilizar

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

Si ADO utilizar

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

cn ser una conexión ADO válido, @@Identity devolverá el último Identity (Autonumber) insertado en esta conexión.

Tenga en cuenta que @@Identity podría ser problemático debido a que el último valor generado puede no ser el que usted está interesado. Para el motor de base de datos Access, considere un VIEW que une dos tablas, las cuales tienen la propiedad IDENTITY, y INSERT INTO el VIEW. Para SQL Server, considere si hay activadores que a su vez insertan registros en otra tabla que también tiene la propiedad IDENTITY.

BTW DMax no funcionaría como si alguien más insertara un registro justo después de haber insertado un registro pero antes de que su función Dmax termine de ejecutarse obtendrá su registro.

+14

DAO pueden hacer SELECT @@ IDENTITY, también - que no es necesario ADO. Hago esto todo el tiempo: lngID = db.OpenRecordset ("SELECT @@ IDENTITY") (0), donde "db" es la misma variable de base de datos que se utilizó para ejecutar la inserción. Ya no abro conjuntos de registros y agrego para esto. –

41

En su ejemplo, como usa CurrentDB para ejecutar su INSERT, lo ha hecho más difícil para usted. En su lugar, esto funcionará:

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 

que solía hacer añade al abrir un conjunto de registros AddOnly y recogiendo el ID de allí, pero esto es mucho más eficiente. Y, tenga en cuenta, Tony, que no requiere ADO.

+2

y funciona incluso cuando el conjunto de registros es una tabla vinculada de SQL Server. Maravilloso –

+0

también puede agregar dbFailOnError como una opción para Ejecutar. De lo contrario, Access no dirá nada si falla. ----- db.Execute query, dbFailOnError – JustJohn

+0

@iDevlop SQL Server es compatible con [la sintaxis 'SELECT @@ IDENTITY'] (https://msdn.microsoft.com/en-us/library/ms187342.aspx). Sería interesante ver qué sucede en otros tipos de tablas vinculadas como Excel u otros RDBMS como Oracle o MySQL. –

3

Esta es una adaptación de mi código para usted. Me inspiré en developpez.com (busque en la página "Pour insérer des données, vaut-il mieux passer par un RecordSet ou par une requête de type INSERT?"). Ellos explican (con un poco de francés). De esta manera es mucho más rápido que el superior. En el ejemplo, esta forma fue 37 veces más rápida. Intentalo.

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

¿Podría identificar qué ejemplo en particular es "37 veces más rápido" que? –

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

No veo cómo responde esto a la pregunta original. Por favor agregue contexto para ver cómo encaja esto? – GPI

+1

Esta respuesta no está clara. Por favor agregue explicaciones. No todos nosotros sabemos ** todo ** sobre vba. – MJH

Cuestiones relacionadas