2009-10-27 5 views
31

J'ai une table JET avec un numéro automatique comme clé primaire, et je voudrais savoir comment je peux 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 suis pas sûr de la fiabilité de cette ligne. Quelques exemples de code:Valeur de numérotation automatique de la dernière ligne insérée - MS Access/VBA

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 fonctionne pas, puisque Execute() ne reviendra pas la valeur de la clé primaire, mais cela est essentiellement le genre de code que je cherche. Je vais devoir utiliser la clé primaire de la nouvelle ligne pour mettre à jour un nombre de lignes dans une autre table.

Quelle serait la manière la plus simple/la plus lisible de le faire?

Répondre

32

Si DAO utilise

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

Si ADO utilise

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

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

Notez que @@Identity pourrait être gênant parce que la dernière valeur générée peut ne pas être celui qui vous intéresse. Pour le moteur de base de données Access, envisager une VIEW qui joint deux tables, qui ont tous deux la propriété IDENTITY, et vous INSERT INTO le VIEW. Pour SQL Server, considérez s'il existe des déclencheurs qui à leur tour insèrent des enregistrements dans une autre table qui a également la propriété IDENTITY. DMW DMax ne fonctionnerait pas comme si quelqu'un d'autre insérait un enregistrement juste après avoir inséré un enregistrement mais avant que votre fonction Dmax finisse de s'exécuter, vous obtiendriez leur enregistrement.

+14

peut OAC ne SELECT @@ IDENTITY, trop - vous n'avez pas besoin ADO. Je le fais tout le temps: lngID = db.OpenRecordset ("SELECT @@ IDENTITY") (0), où "db" est la même variable de base de données qui a été utilisée pour exécuter l'insertion. Je n'ouvre plus les recordsets et ajoute pour cela. –

41

Dans votre exemple, parce que vous utilisez CurrentDB pour exécuter votre INSERT, vous l'avez rendu plus difficile pour vous. 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 

que je faisais ajoute en ouvrant un jeu d'enregistrements AddOnly et ramasser l'ID de là, mais cela est beaucoup plus efficace. Et, notez, Tony, que cela ne nécessite pas ADO.

+2

et cela fonctionne même lorsque le jeu d'enregistrements est une table liée SQL Server! Formidable ! –

+0

vous pouvez également ajouter dbFailOnError en tant qu'option à l'exécution. Sinon, l'accès ne dira rien s'il échoue. ----- db.Exécuter une requête, dbFailOnError – JustJohn

+0

@iDevlop SQL Server prend en charge [la syntaxe 'SELECT @@ IDENTITY'] (https://msdn.microsoft.com/fr-fr/library/ms187342.aspx). Il serait intéressant de voir ce qui se passe dans d'autres types de tables liées comme Excel, ou d'autres SGBDR comme Oracle ou MySQL. –

3

Ceci est une adaptation de mon code pour vous. Je me suis inspiré de developpez.com (Regardez dans la page pour: "Pour insérer des données, vaut mieux passer par un RecordSet ou par une requête de type INSERT?"). Ils expliquent (avec un peu de français). Cette voie 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

+3

Pourriez-vous s'il vous plaît identifier quel exemple particulier est "37 fois plus rapide" 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

Je ne vois pas comment cela répond à la question initiale. S'il vous plaît ajouter le contexte pour voir comment cela correspond? – GPI

+1

Cette réponse n'est pas claire. S'il vous plaît ajouter des explications. Nous ne savons pas tous ** tout ** sur vba. – MJH

Questions connexes