I. Tables et champs▲
II. Requêtes▲
III. Formulaire et états▲
IV. Macros▲
V. VBA▲
V-A. Propositions générales▲
Avec le souci de conserver les anciennes entrées pour ne pas perdre les liens dans les messages sur les forums, il faudrait supprimer les mentions concernant les anciennes technos, notamment pour cocher la référence à une ancienne librairie comme DAO :
Microsoft DAO 3.x Object Library
V-B. Dates et heures▲
IV-B-1. Afficher des durées supérieures à 24 heures ? - [MAJ]▲
Afficher des durées supérieures à 24 heures ?
Peut-être rajouter une fonction qui calcule la durée entre 2 dates en HMS :
Public
Function
DureeHMS
(
ByVal
dt1 As
Date
, ByVal
dt2 As
Date
) As
String
Dim
h As
Double
, m As
Double
, s As
Double
s =
DateDiff
(
"s"
, dt1, dt2) ' nombre de secondes entre les 2 dates
h =
Int
(
Round
(
s /
3600
#, 5
)) ' nombre d'heures avec correction de l'opération portant sur des nombres en virgule flottante
s =
s -
h *
3600
# ' reste de secondes après division entière
m =
Int
(
Round
(
s /
60
#, 5
)) ' nombre de minutes dans le reste
s =
s -
m *
60
# ' reste de secondes
' affichage du résultat HH:MM:SS
DureeHMS =
h &
":"
&
Format
(
m, "00"
) &
":"
&
Format
(
s, "00"
)
End
Function
Ou bien la durée entre deux dates en JHMS :
Public
Function
DureeJHMS
(
ByVal
dt1 As
Date
, ByVal
dt2 As
Date
) As
String
Dim
j As
Double
, h As
Double
, m As
Double
, s As
Double
s =
DateDiff
(
"s"
, dt1, dt2) ' nombre de secondes entre les 2 dates
j =
Int
(
Round
(
s /
(
3600
# *
24
#), 5
)) ' nombre de jours avec correction de l'opération portant sur des nombres en virgule flottante
s =
s -
j *
(
3600
# *
24
#) ' reste de secondes
h =
Int
(
Round
(
s /
3600
#, 5
)) ' nombre d'heures
s =
s -
h *
3600
# ' reste de secondes
m =
Int
(
Round
(
s /
60
#, 5
)) ' nombre de minutes dans le reste
s =
s -
m *
60
# ' reste de secondes
' affichage du résultat HH:MM:SS
DureeJHMS =
j &
" jour(s) "
&
Format
(
h, "00"
) &
":"
&
Format
(
m, "00"
) &
":"
&
Format
(
s, "00"
)
End
Function
Peut-être avertir que comme les dates sont stockées sous forme de numériques (réels doubles) les opérations (addition, soustraction, etc..) portant sur ces nombres en virgule flottante peuvent entraîner des erreurs (avec un lien).
V-B-2. Comment calculer l'age d'une personne ? - [MAJ]▲
Comment calculer l'age d'une personne ?
Une petite explication au début sur ce que fait la fonction :
Il faut retrancher 1 à votre calcul si le mois en cours est inférieur au mois de la date de naissance, ou bien s'il est égal et si le jour d'aujourd'hui est inférieur au jour de la date de naissance :
Peut-être simplifier la 1re fonction :
Function
CalculAge
(
ByVal
Dat1 As
Date
, ByVal
Dat2 As
Date
) As
Integer
CalculAge =
DateDiff
(
"yyyy"
, Dat1, Dat2)
If
(
Month
(
Dat2) <
Month
(
Dat1)) Or
(
Month
(
Dat2) =
Month
(
Dat1)) And
(
Day
(
Dat2) <
Day
(
Dat1)) Then
CalculAge =
CalculAge -
1
End
If
End
Function
Pour la seconde fonction juste avertir que dans le cas où le 1er argument est omis, alors DateReference est égal à 0, ce qui équivaut à #30/12/1899# (Format(0,"dd/mm/yyyy"))
V-B-3. Comment éviter le problème de format de date (le jour et le mois sont parfois inversés) ? - [MAJ]▲
Comment éviter le problème de format de date (le jour et le mois sont parfois inversés) ?
Dim
madate As
Date
madate =
Date
DoCmd.RunSQL
"Insert into table1 (ladate) values("
&
CDbl
(
madate) &
")"
DoCmd.RunSQL
"Insert into table1 (ladate) values(#"
&
Format
(
madate,"mm/dd/yyyy"
) &
"#)"
DoCmd.RunSQL
"Insert into table1 (ladate) values('"
&
madate &
"')"
V-B-4. Comment savoir si un jour est ouvré ? - [MAJ + Nouvelles entrées]▲
Comment savoir si un jour est ouvré ?
Proposition d'ajout d'entrées :
Comment savoir si un jour est férié à partir des jours enregistrés dans une table ?
On dispose d'une table T_JoursFeries(JourFerie) pour enregistrer les jours fériés :
' la fonction renvoie True si le jour passé en argument est férié et false dans le cas contraire
Function
EstFerie
(
ByVal
dt As
Date
) As
Boolean
EstFerie =
Not
IsNull
(
DLookup
(
"JourFerie"
, "T_JoursFeries"
, "JourFerie=#"
&
Format
(
dt, "mm/dd/yyyy"
) &
"#"
))
End
Function
Comment savoir si un jour est chômé à partir des périodes de congés enregistrées dans une table ?
On dispose d'une tableT_Conges(DateDebut, DateFin,..) pour enregistrer les périodes des différents congés :
' la fonction renvoie True si le jour passé en argument est chômé et false dans le cas contraire
Public
Function
EstConge
(
ByVal
dt As
Date
) As
Boolean
EstConge =
Not
IsNull
(
DLookup
(
"DateDebut"
, "T_Conges"
, "#"
&
Format
(
dt, "mm/dd/yyyy"
) &
"# between [DateDebut] and [DateFin]"
))
End
Function
V-B-5. Déterminer la date du premier jour d'une semaine ? - [MAJ]▲
Déterminer la date du premier jour d'une semaine ?
Préciser que la 1ère semaine de l'année ISO correspond à la semaine du premier jeudi de l'année civile.
avec un lien :
https://fr.wikipedia.org/wiki/Num%C3%A9rotation_ISO_des_semaines
V-C. VBA -> SQL▲
V-C-1. Comment créer un jeu de données (Recordset) ? - [MAJ]▲
Comment créer un jeu de données (Recordset) ?
coquille avec '\' devant ' dans les critère du code SQL :
Sub
DAOOpenRecordset (
)
Dim
db As
DAO.Database
, rst As
DAO.Recordset
, fld As
DAO.Field
Dim
sSQL As
String
' Ouverture de la base de données
Set
db =
DBEngine.OpenDatabase
(
".\Comptoir.mdb"
)
sSQL =
"Select * From CLIENTS Where Région= 'WA'"
' Ouverture du Recordset
Set
rst =
db.OpenRecordset
(
sSQL, dbOpenForwardOnly, dbReadOnly)
' Fermeture du Recordset
rst.Close
End
Sub
Peut-être remplacer aussi Set db = DBEngine.OpenDatabase (".\Comptoir.mdb") par simplement set db = Currentdb.
V-C-2. Comment parcourir un jeu d'enregistrements (Recordset) ? - [MAJ]▲
Comment parcourir un jeu d'enregistrements (Recordset) ?
coquille au début du code + supprimer référence DAO :
If
Not
rst.EOF
Then
rst.MoveFirst
While
Not
rst.Eof
' Code
rst.MoveNext
Wend
else
Msgbox
"Le jeu d'enregistrements est vide"
End
if
V-C-3. Comment exécuter une requête action (ajout, suppression ou mise à jour) ? - [MAJ]▲
Comment exécuter une requête action (ajout, suppression ou mise à jour) ?
coquille avec '\' dans les critère du SQL :
Sub
DAOExecuteBulkOpQuery
(
)
Dim
db As
DAO.Database
Set
db =
DBEngine.OpenDatabase
(
".\Comptoir.mdb"
)
' Exécution de la requête
db.Execute
"Update CLIENTS Set PAYS = 'États-Unis' Where PAYS = 'USA'"
Debug.Print
"Records Affected = "
&
db.RecordsAffected
db.Close
End
Sub
Peut-être remplacer aussi Set db = DBEngine.OpenDatabase (".\Comptoir.mdb") par simplement Set db = Currentdb.
V-C-4. Pourquoi les messages d'avertissement n'apparaissent-ils pas lorsque j'exécute mes requêtes action en VBA ? - [MAJ]▲
Docmd.RunSql
""
Update MATABLE Set
MATABLE.
[MONCHAMP] =
""
DVP.COM
""
;"
Guillemet en trop à gauche :
Docmd.RunSql
"Update MATABLE Set MATABLE.[MONCHAMP] = ""DVP.COM"";"
V-C-5. Comment insérer dans une table une chaîne de caractères contenant des quotes - [MAJ]▲
Comment insérer dans une table une chaîne de caractères contenant des quotes ?
La solution consiste à encadrer la chaîne par des guillemets :
val =
"l'exemple"
set
rst=
currentdb.openrecordset
(
"select * from Table1 where Champ1 like "
&
chr
(
34
) &
val &
chr
(
34
) &
"
V-C-6. Comment faire une requête qui recherche les doublons dans une table ? - [MAJ]▲
Comment faire une requête qui recherche les doublons dans une table ?
Count au lieu de sum + Having Count(TABLE1.CHAMP2)>1 pour ne garder que les doublons :
Select
TABLE1.CHAMP1, Count
(
TABLE1.CHAMP2)
AS
CHAMP2 Into
TABLE2
From
TABLE1
Group
By
TABLE1.CHAMP1
Having
Count
(
TABLE1.CHAMP2)>
1
Order
By
TABLE1.CHAMP1
V-C-7. Est-il possible de créer une requête paramétrée dont la valeur du paramètre proviendrait d'une variable ? - [MAJ]▲
Pas de déclaration de variables ni de libération de variable :
dim
qdf as
DAO.QueryDef
Set
qdf=
CurrentDb.QueryDefs
(
"TA_REQUETE"
)
With
qdf
.Parameters
(
"TON_PARAM"
) =
TaVariable
.Execute
End
With
Set
qdf=
Nothing
Proposition d'ajout :
Requête paramétré avec recordset :
dim
qdf as
DAO.QueryDef
dim
rst as
DAO.RecordSet
Set
qdf=
CurrentDb.QueryDefs
(
"TA_REQUETE"
)
With
qdf
.Parameters
(
"TON_PARAM"
) =
TaVariable
set
rst =
.OpenRecordSet
(
)
End
With
' ...
Set
qdf=
Nothing
Set
rst=
Nothing
V-D-8. Comment chercher les enregistrements contenant une certaine chaîne (like) ? - [MAJ]▲
Comment chercher les enregistrements contenant une certaine chaîne (like) ?
coquille avec '\' dans les critère du SQL :
requete =
"Select * From carnet Where Prénom Like '*"
&
prenom &
"*'"
V-C-9. Comment filtrer les données en fonction de la valeur d'un paramètre ? - [Nouvelle entrée]▲
En utilisant la fonction Eval pour obtenir dans la chaîne SQL la valeur de la zone de texte :
Dim
rst as
DAO.RecordSet
Set
rst =
CurrentDb.OpenRecordset
(
"select * from Table1 where champ1 = Eval('Forms!Formulaire1!ZoneTexte1');"
)
En déterminant à l'extérieur la valeur de ZoneTexte1 pour l'insérer ensuite dans la chaîne SQL :
Si le paramètre contient un numérique :
set
rst=
currentdb.openrecordset
(
"select * from Table1 where Champ1 = "
&
forms!Formulaire1!ZoneTexte1 &
";"
)
Si le paramètre contient du texte :
set
rst=
currentdb.openrecordset
(
"select * from Table1 where Champ1 = "
&
chr
(
34
) &
forms!Formulaire1!ZoneTexte1 &
chr
(
34
) &
";"
)
Si le paramètre contient une date :
set
rst=
currentdb.openrecordset
(
"select * from Table1 where Champ1 = #"
&
Format
(
forms!Formulaire1!ZoneTexte1,"mm/dd/yyyy"
) &
"#;"
)
V-D. Numérotation enregistrements▲
V-D-1. Créer son propre numéro-auto - [Nouvelle entrée]▲
En local :
On dispose d'une table Chantiers(IdChantier, RefChantier, ...), IdChantier étant le champ de type entier long contenant la valeur à incrémenter :
Private
Sub
Form_BeforeUpdate
(
Cancel As
Integer
)
' procédure exécutée sur l'événement BeforeUpdate du formulaire F_Dossier
Dim
cpt As
Long
' compteur des numéros automatiques, valeur enregistrée dans la table CompteursIndices
Dim
dbs As
DAO.Database
' variable objet pour faire référence à la base de données
Dim
rst As
DAO.Recordset
' variable objet de type recordset basée sur la table CompteursIndices
If
Me.NewRecord
Then
' si on est en mode ajout
Set
dbs =
CurrentDb ' référence à la base de données courante
' ouverture du recordset basé sur la table CompteursIndicese filtrée en fonction du nom de la table
Set
rst =
dbs.OpenRecordset
(
"select Max(IdChantier) As cpt from Chantier;"
, dbOpenDynaset)
If
Not
rst.EOF
Then
' si un compteur existe pour la période
cpt =
rst!cpt +
1
' on évalue le prochain numéro à attribuer à l'enregistrement
Else
' sinon
' on ajoute la nouvelle période à la table des compteurs d'indices et on met le compteur à 1
cpt =
1
' on repart de 1 pour une autre année
End
If
Me.IdChantier
=
cpt ' on enregistre la valeur du nouveau numéro du chantier dans le champ IdChantier.
' libération des variables objet
rst.Close
Set
rst =
Nothing
Set
dbs =
Nothing
End
If
End
Sub
En mode multiutilisateurs :
On dispose d'une table de compteur d'indice CompteursIndices(NomTable, CompteurIndice).
Un formulaire basé sur la table Chantiers avec sur l'événement avant insertion ce code qui permet d'incrémenter le compteur :
Private
Sub
Form_BeforeUpdate
(
Cancel As
Integer
)
' procédure exécutée sur l'événement BeforeUpdate du formulaire F_Dossier
Dim
cpt As
Long
' compteur des numéros automatiques, valeur enregistrée dans la table T_Compteur_Indice
Dim
dbs As
DAO.Database
' variable objet pour faire référence à la base de données
Dim
rstCpt As
DAO.Recordset
' variable objet de type recordset basée sur la table T_Compteur_Indice
If
Me.NewRecord
Then
' si on est en mode ajout
Set
dbs =
CurrentDb ' référence à la base de données courante
' ouverture du recordset basé sur la table CompteursIndicese filtrée en fonction du nom de la table
Set
rstCpt =
dbs.OpenRecordset
(
"select compteurIndice from T_Compteur_Indice where NomTable like """
&
Me.RecordSource
&
""""
, dbOpenDynaset)
If
Not
rstCpt.EOF
Then
' si un compteur existe pour la période
cpt =
rstCpt!CompteurIndice +
1
' on évalue le prochain numéro à attribuer à l'enregistrement
rstCpt.Edit
rstCpt!CompteurIndice =
cpt ' on met à jour le compteur d'indice avec le numéro
rstCpt.Update
Else
' sinon
' on ajoute la nouvelle période à la table des compteurs d'indices et on met le compteur à 1
cpt =
1
' on repart de 1 pour une autre année
rstCpt.AddNew
rstCpt!NomTable =
Me.RecordSource
rstCpt!CompteurIndice =
cpt
rstCpt.Update
End
If
Me.IdChantier
=
cpt ' on enregistre la valeur du nouveau numéro du chantier dans le champ IdChantier.
' libération des variables objet
rstCpt.Close
Set
rstCpt =
Nothing
Set
dbs =
Nothing
End
If
End
Sub
V-E. Opération sur les nombres▲
V-E-1. Comment convertir un nombre décimal en binaire ?▲
Comment convertir un nombre décimal en binaire ?
' convertit un entier décimal 11 en nombre binaire 1011
' suivant un schéma binaire : 11 = 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0
Public
Function
DecimalToBinaire
(
ByVal
NbreDec As
Double
) As
String
' Variable/Indice de boucle et valeur binaire du digit correspondant
Dim
IndicePos As
Integer
, ValDig As
Integer
' Variable/Indice de poids fort du nombre binaire
Dim
IndiceMax As
Integer
' calcul l'indice de poids fort du nombre binaire avec correction des erreurs liées aux opérations en virgule flottante
If
NbreDec >
0
# Then
IndiceMax =
Int
(
Round
(
Log
(
NbreDec) /
Log
(
2
), 9
))
For
IndicePos =
IndiceMax To
0
Step
-
1
ValDig =
Int
(
NbreDec /
(
2
# ^
IndicePos)) ' valeur binaire du digit de position IndicePos
DecimalToBinaire =
DecimalToBinaire &
ValDig
NbreDec =
NbreDec -
ValDig *
(
2
# ^
IndicePos) ' reste de la division
Next
IndicePos
End
Function
' convertit un entier décimal 11 en nombre binaire 1011
' suivant un schéma de horner : 11 = 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0 = 1 + 2*(1 + 2*(0 + 2*1)
Public
Function
DecimalToBinaire2
(
ByVal
NbreDec As
Double
) As
String
' Variable/Indice de boucle et valeur binaire du digit correspondant
Dim
IndicePos As
Integer
, ValDig As
Integer
' Variable/Indice de poids fort du nombre binaire
Dim
IndiceMax As
Integer
' calcul l'indice de poids fort du nombre binaire avec correction des erreurs liées aux opérations en virgule flottante
If
NbreDec >
0
Then
IndiceMax =
Int
(
Round
(
Log
(
NbreDec) /
Log
(
2
), 9
))
For
IndicePos =
0
To
IndiceMax
ValDig =
NbreDec -
Int
(
NbreDec /
2
#) *
2
# ' reste de la division de NbreDec par 2
DecimalToBinaire2 =
ValDig &
DecimalToBinaire2
NbreDec =
Int
(
NbreDec /
2
#)
Next
IndicePos
End
Function
V-E-2. Comment convertir un nombre binaire en décimal ? - [Nouvelle entrée] ▲
Proposition d'entrée :
Comment convertir un nombre binaire en décimal ?
' convertit un nombre binaire 1011 en nombre décimal 11
' suivant un schéma binaire : 11 = 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0
Public
Function
BinaireToDecimal
(
ByVal
NbreBin) As
Double
' Variable/Indice de boucle
Dim
IndicePos As
Integer
' Variable/Indice de pois fort
Dim
IndiceMax As
Integer
' calcul du nombre de positions du résultat en binaire avec correction des erreurs liées aux opérations en virgule flottante
IndiceMax =
Len
(
NbreBin) -
1
For
IndicePos =
0
To
IndiceMax
BinaireToDecimal =
BinaireToDecimal +
(
Mid
(
NbreBin, IndiceMax -
IndicePos +
1
, 1
) *
(
2
^
IndicePos))
Next
IndicePos
End
Function
V-E-3. Comment corriger les erreurs dans les résultats des opérations en virgule flottante ? - [Nouvelle entrée] ▲
Il faut arrondir le résultat en utilisant la fonction Rownd() :
resultat =
Round
(
Resultat,5
)
V-F. Formulaires - Sous-formulaires▲
V-F-1. Faire référence à un contrôle dans un formulaire▲
Dans le formulaire actif pour copier dans une variable la valeur du contrôle nommé "total" :
val =
Me!total
Dans un formulaire ouvert nommé "frmFacture" :
val =
Forms!frmFacture!total
V-F-2. Faire référence à un contrôle dans un sous-formulaire▲
Pour copier dans une variable la valeur du contrôle nommé "total" situé dans le sous-formulaire "sfrmDetailFacture" :
val =
Me!sfrmDetailFacture.form
!total
V-F-3. Exécuter une procédure contenue dans le module d'un sous-formulaire▲
Pour exécuter la procédure proc() situé dans le module du sous-formulaire actif sfrmDetailFacture :
M_sfrmDetailFacture.Proc
(
)
Autre possibilité :
Forms!frmFacture!sfrmDetailFacture.Form.Proc
(
)
V-G. Etats▲
V-G-1. Comment exporter un état au format Word ?▲
V-G-2. Comment exporter un état au format pdf ? - [Nouvelle entrée]▲
V-H. Interaction avec d'autres applications▲
V-H-1. Comment ouvrir un fichier HTML, Word, PDF ou autre en utilisant l'exécutable associé ?▲
V-H-2. Comment ouvrir un dossier à l'aide de la fonction Shell ? - [Nouvelle entrée]▲
Shell "explorer.exe "
&
Chr
(
34
) &
CheminDossier &
Chr
(
34
), vbMaximizedFocus ' on ouvre le dossier avec son chemin
V-H-3. Comment ouvrir un fichier à l'aide de la fonction Shell ? - [Nouvelle entrée]▲
Shell "explorer.exe "
&
Chr
(
34
) &
CheminFichier &
Chr
(
34
), vbMaximizedFocus ' on ouvre le fichier avec son chemin