Il est de bon ton de se souhaiter la bonne année. Mais vous, et vous seul, pourrez faire en sorte que cette année soit bonne, meilleure que celle qui vient de s'écouler. Apprenez à ne compter que sur vous, car personne n'est plus qualifié que vous-même pour bâtir, réparer ou améliorer votre propre vie. Personne ne fera les choses à votre place. D'ailleurs, tout ce que les autres peuvent faire, c'est souhaiter que vous le fassiez. Et ne croyez pas que tout ceux qui vous entourent vous apporteront des solutions : certains font juste partie de vos problèmes. Transformez vos résolutions en actes, et dans douze mois, retournez-vous et souriez-vous fièrement : C'était long. C'était difficile. Mais ça y est : 2017 était une bonne année, merci Moi.

Utilisation des Recordset

Généralités sur les Recordset

Toutes les recherches d'enregistrements et les accès aux données passent par OpenRecordet (il n'y a pas de CreateRecordSet). Voici un exemple type de préparation à l'accès aux données :

Dim MaTable As Recordset
Set MaTable = DBEngine.Workspaces(0).Databases(0).OpenRecordset("T_Client")

Il existe 3 sortes de Recordset :

Dynaset

Le plus souple. Permet des modifications sur des requêtes, mais c'est le plus lent. N'accepte pas la méthode Seek

Table

Le plus rapide, mais les Recordset de type table ne permettent pas les requêtes. Ce genre de RecordSet permet la méthode Seek, la plus rapide

Snapshot

Photo du RecordSet à un moment donné. On ne peut ni ajouter, ni modifier, ni supprimer un enregistrement dans un SnapShot.

Attention donc, lorsqu'on crée un RecordSet sans préciser si c'est un Dynaset, un Snapshot ou un Table, Jet choisit le type qu'il pense le plus approprié. Mais comme toutes les méthodes ne sont pas applicables sur tous les types de RecordSet, mieux vaut les déclarer explicitement.

RecordSetClone

RecordSetClone est une instruction qui permet d'obtenir rapidement la copie conforme d'un formulaire que l'on peut ensuite utiliser comme en DAO

L'exemple suivant reprend exactement ce qui se passe quand on demande une liste déroulante avec l'assistant, et qu'on veut que le résultat du choix de cette liste cherche un enregistrement dans ce même formulaire :

Dim CeFormulaire As Recordset, entI As Integer
Set CeFormulaire = Me.RecordsetClone
CeFormulaire.MoveFirst
MsgBox CeFormulaire("NomFruit")
CeFormulaire.Close

Move[X|Next|Last|Previous|First]

Cet exemple se positionne :

  1. Sur le premier enregistrement
  2. Sur le deuxième enregistrement
  3. Sur le dernier enregistrement
  4. Sur l'avant-dernier enregistrement

De la table T_Client, et affiche le prénom de chacun.

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("T_Client")
Enr.MoveFirst
MsgBox Enr("Prenom")
Enr.MoveNext
MsgBox Enr("Prenom")
Enr.MoveLast
MsgBox Enr("Prenom")
Enr.MovePrevious
MsgBox Enr("Prenom")

Atteinte des limites du RecordSet avec MoveXXX

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("T_Client")
Enr.MoveLast ' Se positionne sur le dernier enregistrement
MsgBox Enr.EOF ' Renvoie FAUX
Enr.MoveNext ' Ne crée pas d'erreur
MsgBox Enr.EOF ' Renvoie Vrai
MsgBox Enr("Prenom") ' Renvoie l'erreur "Pas d'enregistrement courant"
Enr.MoveFirst ' Se positionne sur le premier enregistrement
MsgBox Enr.BOF ' Renvoie FAUX
Enr.MovePrevious ' Ne crée pas d'erreur
MsgBox Enr.BOF ' Renvoie Vrai
MsgBox Enr("Prenom") ' Renvoie l'erreur "Pas d'enregistrement courant"

Enr.MovePrevious ' Renvoie immédiatement une erreur puisque nous sommes déjà avant le premier enregistrement

Dans le cas ou le RecordSet ne contient aucun enregistrement, les méthodes MoveXXX renvoient toutes une erreur. Les propriétés BOF et EOF sont toutes les deux vraies en même temps.

Move X

Il est possible de se déplacer en avant comme en arrière de X enregistrement avec cette méthode

Cet exemple positionne le pointeur d'abord sur le premier enregistrement avec MoveFirst, ensuite il avance de 3 enregistrements et revient en arrière de deux. Attention à ne pas oublier de placer l'Index correctement pour ne pas avoir des surprises.

NomPersonne

Prenom

defawes michel
pochon pierre
rivares maria
allen woody

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("T_Personne")
Enr.MoveFirst
MsgBox Enr("NomPersonne") Affiche defawes
Enr.Move 3 Pointe sur allen
Enr.Move -1 Pointe sur rivares
MsgBox Enr("NomPersonne") affiche rivares

Dans le cas ou on essaie de se déplacer manifestement en dehors de la table par de trop grandes valeurs de Move, pas d'erreur n'est générée si on ne demande pas le contenu. On peut toujours tester si on seors de la table avec BOF et EOF

Utilisation des Index avec les MoveXXX

Soit la table T_Personne :

NomPersonne

Prenom

de funès Louis
allen woody
delon alain
lhermitte thierry

Nous allons maintenant utiliser la méthode MoveFirst, mais avec des Index différents. La table doit avoir ses deux champs indexés (NomPersonne et Prenom).

 

Dans ce premier cas, le MoveFirst nous envoie sur le premier enregistrement alphabétique NomPersonne, càd ALLEN (Woody)

Dim rec As Recordset
Set rec = CurrentDb.OpenRecordset("T_Personne")
rec.Index = "NomPersonne"
rec.MoveFirst
MsgBox rec("Prenom") & " " & rec("NomPersonne")

Dans ce deuxième cas, par contre, comme l'index est défini comme étant Prenom, le MoveFirst nous renvoie sur le premier enregistrement du RecordSet, mais en prenant comme base alphabétique Prenom, et c'est donc ALAIN (Delon) qui va sortir.

rec.Index = "Prenom"
rec.MoveFirst
MsgBox rec("Prenom") & " " & rec("NomPersonne")

Modifier les enregistrements

EOF, MoveNext, Edit, Update

Dans cet exemple, on ouvre la base de données test.mdb, on ouvre la table des fournisseurs, on recherche les fournisseurs dont le nom est Kuhn, et on les remplace par Rivares. Ensuite, on ferme la base de données.

Dim MaTable As Recordset
Set MaTable = CurrentDB.OpenRecordset("T_Client")
Do Until MaTable.
EOF = True
If MaTable("NomClient") = "Kuhn" Then
MaTable.
Edit
MaTable("NomClient") = "Rivares"
MaTable.
UPDATE
End If
MaTable.
MoveNext
Loop
MaTable.Close

Mise à jour : Update, CancelUpDate

Admettons que nous sommes dans un formulaire en mode continu, et que nous voyons l'ensemble de tous nos enregistrements sur le même écran. Si on est dans un enregistrement quelconque, et qu'on modifie par DAO la valeur d'un champ du premier enregistrement, tout se passe bien, mais nous n'avons de preuve visuelle que lorsque nous cliquons sur un champ appartement au premier enregistrement. Afin d'apporter immédiatement la preuve visuelle, il faut appliquer la méthode Requery, comme dans l'exemple qui suit.

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("T_Client")
Enr.MoveFirst
Enr.Edit
Enr("NomClient") = "POUPONNOT"
Enr.Update
' Et si on avait fait Enr.CancelUpdate, l'enregistrement n'aurait pas été modifié
Enr.Close
Me.Requery

Date de création d'une table : DateCreated

Attention : DateCreated ne peut s'utiliser que sur des objets de type Table

Set TableFruit = CurrentDb.OpenRecordset("T_Fruit", dbOpenTable)
Set TableFruit = CurrentDb.OpenRecordset("T_Fruit", dbOpenDynaset) ' N'aurait pas permis DateCreated
MsgBox TableFruit.DateCreated

A quelle position sommes nous ? AbsolutePosition

Il est possible de savoir au combientième enregistrement nous nous trouvons. Par exemple :

Dim TableFruit As Recordset
Set TableFruit = CurrentDb.OpenRecordset("T_Fruit", dbOpenDynaset)
TableFruit.MoveFirst
MsgBox TableFruit.AbsolutePosition
' Absolute position = 0
TableFruit.MoveNext
MsgBox TableFruit.AbsolutePosition
' Absolute position = 1
TableFruit.MoveLast
' Absolute position = le nombre d'enregistrements moins 1
MsgBox TableFruit.AbsolutePosition
TableFruit.Close

Récupérer des enregistrements en tableau avec GetRows

Il est possible de récupérer des enregistrement dans un tableau à l'aide de GetRows (NombreDEnregistrements). Dans cet exemple, nous prenons cette table dont la propriété Index est à NomPersonne. Nous imaginons également que nous sommes positionné sur le premier enregistrement (woody allen), car nous pourrions être ailleurs avec la méthode MoveXXX par exemple, auquel cas la récupération des données en tableau commencerait à la position courante

IDPersonne

NomPersonne

Prenom

Age

0

1

2

3

0

4 (0,0)

allen (1,0) woody (2,0)

50 (3,0)

1

1 (0,1)

defawes (1,1) michel (2,1)

32 (3,1)

2

5 (0,2)

delon (1,2) alain (2,2)

55 (3,2)

Dim enr As Recordset

Dim Contenu As Variant
Set enr = CurrentDb.OpenRecordset("Personne")
enr.Index = "NomPersonne"
Contenu = enr.GetRows(2) ' 2 est le nombre d'enregistrements, numérotés de 0 à 1
MsgBox Contenu(0, 0) ' 4 (1er champ, 1er enregistrement)
MsgBox Contenu(0, 1) ' 1 (1er champ, 2ème enregistrement)
MsgBox Contenu(1, 0) ' Allen (2ème champ, 1er enregistrement)
MsgBox Contenu(2, 0) ' Woody (3ème champ, 1er enregistrement)
MsgBox Contenu(3, 0) ' 50 (4ème champ, 1er enregistrement)
' Voici le dernier champ du dernier enregistrement possible :
MsgBox Contenu(3, 1) ' 32 (4ème champ, 2ème enregistrement)
' MsgBox (4,0) engendre une erreur car ce serait le 5ème champ (inexistant)
' MsgBox (0,2) engendre une erreur car le GetRows prévoit le stockage des 2 premiers enregistrements rencontrés numérotés de 0 à 1

Index

ATTENTION :

  1. On crée T_Client
  2. On y installe un champ DateNaissance
  3. On l'indexe
  4. On sauve la table
  5. On renomme DateNaissance en DateDeNaissance

Le nom de l'index n'a pas changé : CurrentDB.TableDefs("T_Client").Indexes(0).Name est toujours DateNaissance

Recherche d'enregistrements sur la base d'un index

Seek, NoMatch, Index, Edit, Update

Cet exemple montre comment on recherche dans une table tous les enregistrement dont l’âge est égal à 27, pour les remplacer par 28, et de recommencer l’opération jusqu'à ce qu’il ne reste plus d’enregistrements correspondants. Attention, cet exemple ne marche qu’avec des tables, et le champ recherché par seek doit avoir la proprété indexé à oui. Bien entenu, la méthode seek est bien plus rapide que la méthode find

Dim MaBD As Database, MaTable As Recordset
Set MaBD = DBEngine.Workspaces(0).Databases(0)
Set MaTable = MaBD.OpenRecordset("T_Client", DB_OPEN_TABLE)
MaTable.
Index = "Age"
Do Until MaTable.
NoMatch
MaTable.Seek "=", 27
If Not MaTable.
NoMatch Then
MaTable.
Edit
MaTable("Age") = 28
MaTable.
Update
End If
Loop
MaTable.Close

Attention : La méthode Seek nous renvoie sur un des enregistrements correspondants, s'il en existe, mais on ne pru pas faire

MsgBox Enr("NomClient")

Ca renvoie une erreur

Recherche d'un enregistrement avec Find[First¦Next¦Last¦Previous]

FindFirst

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("Personne", dbOpenDynaset)
Enr.
FindFirst "Prenom = 'Pierre'"
MsgBox Enr("NomPersonne")
Enr.Close

FindFirst recherche le premier enregistrement correpondant aux critères paramétrés. Quand FindFirst ne trouve aucun enregistrement correspondant, il se place sur le premier enregistrement de la table (et encore, c'est pas sûr que ce soit le premier)

Attention _ J'ai testé la méthode FindFirst sur une base de données externe, et ça ne marche que si le nom de la table ne contient pas de trait de soulignement.

Attention : Si on recherche un texte contenant une apostrophe, il faut la doubler pour que pas d'erreur ne soir générée, comme ceci :

MonGroupe.FindFirst "Prenom = 'D''Artagnan'"

Il faut donc doubler automatiquement l'apostrophe, grâce à la fonction maison :

' Cette fonction double les apostrophes éventuels de la chaîne de caractères
' Mot. Ensuite, elle ajoute une apostrophe devant et derrière Mot.
Function Apostrophe(ByVal Mot As String) As String
If InStr(Mot, "'") > 0 Then
Mot = Left$(Mot, InStr(Mot, "'") - 1) & "''" & Right$(Mot, Len(Mot) - InStr(Mot, "'"))
End If
Apostrophe = "'" & Mot & "'"
End Function

On pourra alors chercher correctement dans la table, comme ceci (Attention : Je constate que si on omet la propriété Text de la zone d'édition de recherche, ça ne fonctionne plus.

MonGroupe.FindFirst "Prenom = " & Desapostrophe(Me![edicherche].Text)

FindNext, FindLast, FindPrevious

Il est possible que plusieurs enregistrements correspondent aux critères de FindFirst. C'est pourquoi existent les autres Find.

NomPersonne

Prenom

defawes michel
pochon pierre
rivares maria
rochat pierre

Dans cet exemple, on va rechercher la première occurence de Pierre, puis une deuxième, puis une éventuelle 3ème. Mais comme cette troisième occurence n'existe pas, la propriété NoMatch est mise à Vraie, et le pointeur d'enregistrement reste planté sur la dernière occurence trouvée, sans faire d'erreur.

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("Personne", dbOpenSnapshot)
Enr.FindFirst "Prenom = 'pierre'" ' Se positionne sur pierre pochon
' (Enr.FindNext "Prenom = 'pierre'" aurait aussi fonctionné, j'ai testé)
MsgBox Enr.NoMatch ' FAUX
MsgBox Enr("NomPersonne") ' pochon
Enr.FindNext "Prenom = 'pierre'" ' Se positionne sur pierre rochat
MsgBox Enr.NoMatch ' FAUX
MsgBox Enr("NomPersonne") ' rochat
Enr.FindNext "Prenom = 'pierre'" ' Reste simplement sur pierre rochat
MsgBox Enr.NoMatch ' VRAI
MsgBox Enr("NomPersonne") ' rochat
Enr.Close

Effacer un enregistrement

Delete

Dans cet exemple, on efface le premier enregistrement dont le prénom est Pierre. Attention : Il faut que ce soit un Dynaset ou un Table

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("Personne", dbOpenDynaset)
Enr.FindFirst "Prenom = 'pierre'"
Enr.
Delete
Enr.Close

Baser un RecordSet sur une requête

Il est possible de soit baser un RecordSet sur une requête existante, ou directement en écrivant le code SQL en guise de requête.

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("R_Fournisseur")
MsgBox Enr("NomFournisseur")

Est équivalent à :

Dim Enr As Recordset
Set Enr = CurrentDb.OpenRecordset("SELECT * FROM T_Fournisseur")
MsgBox Enr("NomFournisseur")

Voici un autre exemple ou, cette fois, la requête est paramétrée sur un formulaire de façon à ce qu'elle extraie l'ensemble des enregistrements du sous-formulaire VenteDetail du formulaire Vente. Il est a noter qu'il n'est pas possible de baser un RecordSet sur une requete parametree, car on dirait bien qu'Access refuse d'aller extraire un parametre (par exemple dans un formulaire) au moment ou on le definit comme un Recordset. La seule solution reste la chaine SQL comme dans l'exemple suivant :

Set RequeteListeDetailCetteVente = CurrentDb.OpenRecordset("SELECT * FROM T_VenteDetail Where IDVente = " & Me![IDVente])

Ajouter un nouvel enregistrement à une table avec AddNew

AddNew, Update

Dim MaTable As Recordset
Set MaTable = CurrentDB.OpenRecordset("T_Client", DB_OPEN_TABLE)
MaTable.
AddNew
MaTable("NomClient") = "Dupont"
MaTable.
Update
MaTable.Close

La même chose en utilisant With :

With

Dim MaBase As DATABASE, rst As Recordset
Set MaBase = CurrentDb
Set JeuEnregistrement = MaBase.OpenRecordset("T_Client")
With JeuEnregistrement
.AddNew
![NomClient] = "Russell"
![Prenom] = "Peter"
.UPDATE
End With
MaBase.Close