web-dev-qa-db-fra.com

Valeur de numérotation automatique de la dernière ligne insérée - MS Access / VBA

J'ai une table JET avec un numéro automatique comme clé primaire, et je voudrais savoir comment récupérer ce numéro après avoir inséré une ligne. J'ai pensé à utiliser MAX() pour récupérer la ligne avec la valeur la plus élevée, mais je ne sais pas à quel point ce serait fiable. Quelques exemples de code:

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

Maintenant, je sais que cela ne fonctionnerait pas, car Execute() ne retournera pas la valeur de la clé primaire, mais c'est essentiellement le type de code que je recherche. Je devrai utiliser la clé primaire de la nouvelle ligne pour mettre à jour un certain nombre de lignes dans une autre table.

Quelle serait la manière la plus simple/la plus lisible de procéder?

35
a_m0d

Si DAO utilisez

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

Si ADO utilisez

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

cn étant une connexion valide ADO, @@Identity renverra le dernier Identity (numéro automatique) inséré sur cette connexion.

Notez que @@Identity peut être gênant car la dernière valeur générée peut ne pas être celle qui vous intéresse. Pour le moteur de base de données Access, considérez un VIEW qui joint deux tables, qui ont toutes les deux IDENTITY propriété, et vous INSERT INTO le VIEW. Pour SQL Server, déterminez s'il existe des déclencheurs qui à leur tour insèrent des enregistrements dans une autre table qui possède également la propriété IDENTITY.

BTW DMax ne fonctionnerait pas comme si quelqu'un d'autre insérait un enregistrement juste après que vous en ayez inséré un mais avant que votre fonction Dmax termine son exécution, alors vous obtiendriez son enregistrement.

37
Tony Toews

Dans votre exemple, parce que vous utilisez CurrentDB pour exécuter votre INSERT, vous avez rendu la tâche plus difficile. Au lieu de cela, cela fonctionnera:

  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

J'avais l'habitude de faire des INSERT en ouvrant un jeu d'enregistrements AddOnly et en récupérant l'ID à partir de là, mais c'est ici beaucoup plus efficace. Et notez qu'il ne nécessite pas ADO.

47
David-W-Fenton

Ceci est une adaptation de mon code pour vous. Je me suis inspiré de developpez.com (Cherchez dans la page: " Pour insérer des données, vaut-il mieux passer par un RecordSet ou par une requête de type INSÉRER? "). Ils expliquent (avec un peu de français). Cette façon est beaucoup plus rapide que celle supérieure. Dans l'exemple, cette méthode était 37 fois plus rapide. Essayez-le.

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

5
LeCygne
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
3
Derek Ebrey

Les deux exemples ci-dessus ne fonctionnaient pas pour moi. L'ouverture d'un jeu d'enregistrements sur la table et l'ajout d'un enregistrement fonctionnent pour ajouter l'enregistrement, sauf:

myLong = CLng(rs!AutoNumberField)

renvoie Null s'il est placé entre rs.AddNew et rs.Update. Si mis après rs.Update, il retourne quelque chose, mais c'est toujours faux et toujours la même valeur incorrecte. L'examen du tableau directement après l'ajout du nouvel enregistrement montre une valeur de champ de numérotation automatique différente de celle renvoyée par l'instruction ci-dessus.

myLong = DLookup("AutoNumberField","TableName","SomeCriteria")

fonctionnera correctement, tant qu'il est effectué après rs.Update, et il existe d'autres champs qui peuvent identifier l'enregistrement de manière unique.

0
RMittelman