| | Versions : 97 et supérieures
Important : Pour que ce code fonctionne, vous devez ajouter une référence Microsoft DAO à votre projet.
Voici un exemple de table :
Projet |
NomParticipant |
1 |
Dupont |
1 |
Durand |
1 |
Paul |
2 |
Dupont |
2 |
Luc |
Dans une requête R01, vous souhaitez obtenir la liste des projets ainsi que la liste des participants sur une seule colonne et une seule ligne par projet.
Projet |
LesParticipants |
1 |
Dupont Durand Paul |
2 |
Dupont Luc |
Pour cela, il vous faut placer ce code dans un module : Public Function RecupParticipant(Projet As Long) As String
Dim res As DAO.Recordset
Dim SQL As String
SQL = "SELECT NomParticipant FROM Tbl_Projet WHERE Projet=" & Projet
Set res = CurrentDb.OpenRecordset(SQL)
While Not res.EOF
RecupParticipant = RecupParticipant & res.Fields(0).Value & " "
res.MoveNext
Wend
RecupParticipant = Left(RecupParticipant, Len(RecupParticipant) - 1)
Set res = Nothing
End Function |
Puis créer la requête :
R01 : SELECT DISTINCT Tbl_projet.Projet, Recupparticipant(Projet) AS LesParticipants
FROM Tbl_projet; |
Dans une requête R02, vous souhaitez obtenir la liste des participants ainsi que la liste de leurs projets sur une seule colonne et une seule ligne par participant.
NomParticipant |
LesProjets |
Dupont |
1;2 |
Durand |
1 |
Luc |
2 |
Paul |
1 |
Pour arriver à un tel résultat, placer dans un module le code suivant :
Public Function RecupProjet(Nom As String) As String
Dim res As DAO.Recordset
Dim SQL As String
SQL = "SELECT Projet FROM Tbl_Projet WHERE NomParticipant=" & _
Chr(34) & Nom & Chr(34)
Set res = CurrentDb.OpenRecordset(SQL)
While Not res.EOF
RecupProjet = RecupProjet & res.Fields(0).Value & ";"
res.MoveNext
Wend
RecupProjet = Left(RecupProjet, Len(RecupProjet) - 1)
Set res = Nothing
End Function |
Et enfin, créer la requête SQL :
R02 :
SELECT DISTINCT Tbl_projet.NomParticipant, Recupprojet(NomParticipant) AS LesProjets
FROM Tbl_projet; |
|
| |
Version : Access 2000 et ultérieures
Cet exemple vous permet de classer des données en fonction d'une plage.
Par exemple, le nombre 101 appartient à la tranche 100 à 199 si
l'on considère des plages de 100 éléments.
Placez le code suivant dans un module :
Function fIntervalle(ByVal Valeur As Double, _
Optional ByVal EspaceIntervalle As Double = 25) As String
Dim l1 As Long
Dim l2 As Long
l1 = (Valeur \ EspaceIntervalle) * EspaceIntervalle
If Valeur >= 0 Then
l2 = l1 + EspaceIntervalle - 1
fIntervalle = l1 & " à " & l2
Else
l2 = l1 - EspaceIntervalle + 1
fIntervalle = l2 & " à " & l1
End If
End Function |
Ainsi, Msgbox fIntervalle(101,100) affiche 100 à 199.
Un exemple fréquent d'utilisation est le classement des notes des élèves d'une classe. Prenons l'exemple de la table tblNote suivante :
Eleve |
Note |
Devoir |
PAUL |
12 |
Devoir n°1 |
REMI |
13 |
Devoir n°1 |
MARC |
4 |
Devoir n°1 |
YVES |
3 |
Devoir n°1 |
MARTIN |
5 |
Devoir n°1 |
SIMON |
8 |
Devoir n°1 |
LUC |
9 |
Devoir n°1 |
LUCIE |
3 |
Devoir n°1 |
MARIE |
2 |
Devoir n°1 |
BILL |
0 |
Devoir n°1 |
GERALDINE |
2 |
Devoir n°1 |
SOPHIE |
2 |
Devoir n°1 |
FELICIEN |
17 |
Devoir n°1 |
ANNE |
18 |
Devoir n°1 |
PAUL |
12 |
Devoir n°2 |
REMI |
1 |
Devoir n°2 |
MARC |
3 |
Devoir n°2 |
YVES |
3 |
Devoir n°2 |
MARTIN |
18 |
Devoir n°2 |
SIMON |
17 |
Devoir n°2 |
LUC |
16 |
Devoir n°2 |
LUCIE |
4 |
Devoir n°2 |
MARIE |
5 |
Devoir n°2 |
BILL |
3 |
Devoir n°2 |
GERALDINE |
8 |
Devoir n°2 |
SOPHIE |
10 |
Devoir n°2 |
FELICIEN |
11 |
Devoir n°2 |
ANNE |
19 |
Devoir n°2 |
A l'aide d'une première requête (R01), nous pouvons calculer la répartition des notes.
SELECT fIntervalle(note,5) AS Tranche, *
FROM tblNote
ORDER BY Val(fIntervalle(note,5)); |
Tranche |
Eleve |
Note |
Devoir |
0 à 4 |
YVES |
3 |
Devoir n°2 |
0 à 4 |
LUCIE |
3 |
Devoir n°1 |
0 à 4 |
MARIE |
2 |
Devoir n°1 |
0 à 4 |
BILL |
0 |
Devoir n°1 |
0 à 4 |
GERALDINE |
2 |
Devoir n°1 |
0 à 4 |
SOPHIE |
2 |
Devoir n°1 |
0 à 4 |
MARC |
3 |
Devoir n°2 |
0 à 4 |
YVES |
3 |
Devoir n°1 |
0 à 4 |
MARC |
4 |
Devoir n°1 |
0 à 4 |
LUCIE |
4 |
Devoir n°2 |
0 à 4 |
BILL |
3 |
Devoir n°2 |
0 à 4 |
REMI |
1 |
Devoir n°2 |
5 à 9 |
LUC |
9 |
Devoir n°1 |
5 à 9 |
MARTIN |
5 |
Devoir n°1 |
5 à 9 |
SIMON |
8 |
Devoir n°1 |
5 à 9 |
MARIE |
5 |
Devoir n°2 |
5 à 9 |
GERALDINE |
8 |
Devoir n°2 |
10 à 14 |
REMI |
13 |
Devoir n°1 |
10 à 14 |
PAUL |
12 |
Devoir n°2 |
10 à 14 |
PAUL |
12 |
Devoir n°1 |
10 à 14 |
SOPHIE |
10 |
Devoir n°2 |
10 à 14 |
FELICIEN |
11 |
Devoir n°2 |
15 à 19 |
ANNE |
18 |
Devoir n°1 |
15 à 19 |
ANNE |
19 |
Devoir n°2 |
15 à 19 |
MARTIN |
18 |
Devoir n°2 |
15 à 19 |
SIMON |
17 |
Devoir n°2 |
15 à 19 |
LUC |
16 |
Devoir n°2 |
15 à 19 |
FELICIEN |
17 |
Devoir n°1 |
Puis une seconde nous permet de faire l'analyse croisée des notes afin d'obtenir les tranches en colonne.
TRANSFORM Count(R01.Eleve) AS CompteDeEleve
SELECT R01.Devoir
FROM R01
GROUP BY R01.Devoir
PIVOT R01.Tranche; |
Devoir |
0 à 4 |
5 à 9 |
10 à 14 |
15 à 19 |
Devoir n°1 |
7 |
3 |
2 |
2 |
Devoir n°2 |
5 |
2 |
3 |
4 |
|
| |
Cette section propose plusieurs requêtes pour classer des enregsitrements.
Voici notre table exemple (elle est nommée Tbl_Note) :
Note |
Nom |
10 |
Paul |
12 |
Dupont |
6 |
Henry |
20 |
Luc |
16 |
Marc |
12 |
Etienne |
12 |
Simon |
20 |
Lucien |
1. Classement indexé à zéro des notes par ordre décroissant correspondant à :
Rang |
Note |
Nom |
0 |
20 |
Lucien |
0 |
20 |
Luc |
2 |
16 |
Marc |
3 |
12 |
Simon |
3 |
12 |
Etienne |
3 |
12 |
Dupont |
6 |
10 |
Paul |
7 |
6 |
Henry |
SELECT
(SELECT Count(Note)
FROM tbl_note T2
WHERE T2.Note>T1.Note) AS Rang,
T1.Note, *
FROM tbl_note AS T1
ORDER BY T1.Note DESC; |
Rang |
Note |
Nom |
0 |
20 |
Lucien |
0 |
20 |
Luc |
1 |
16 |
Marc |
2 |
12 |
Simon |
2 |
12 |
Etienne |
2 |
12 |
Dupont |
3 |
10 |
Paul |
4 |
6 |
Henry |
SELECT
(SELECT Count(Note)
FROM (SELECT Distinct Note FROM tbl_note) T2
WHERE T2.Note>T1.Note) AS Rang,
T1.Note, *
FROM tbl_note AS T1
ORDER BY T1.Note DESC; |
2. Classement indexé à zéro des notes par ordre croissant correspondant à :
Rang |
Note |
Nom |
0 |
6 |
Henry |
1 |
10 |
Paul |
2 |
12 |
Simon |
2 |
12 |
Etienne |
2 |
12 |
Dupont |
5 |
16 |
Marc |
6 |
20 |
Lucien |
6 |
20 |
Luc |
SELECT
(SELECT Count(Note)
FROM tbl_Note T2
WHERE T2.Note<T1.Note) AS Rang, T1.Note, *
FROM tbl_note AS T1
ORDER BY T1.Note; |
Rang |
Note |
Nom |
0 |
6 |
Henry |
1 |
10 |
Paul |
2 |
12 |
Simon |
2 |
12 |
Etienne |
2 |
12 |
Dupont |
3 |
16 |
Marc |
4 |
20 |
Lucien |
4 |
20 |
Luc |
SELECT
(SELECT Count(Note)
FROM (SELECT Distinct Note FROM tbl_note) T2
WHERE T2.Note<T1.Note) AS Rang, T1.Note, *
FROM tbl_note AS T1
ORDER BY T1.Note; |
3. Classement indexé à 1 :
Il suffit d'ajouter 1 à chaque ligne
Rang |
Note |
Nom |
1 |
6 |
Henry |
2 |
10 |
Paul |
3 |
12 |
Simon |
3 |
12 |
Etienne |
3 |
12 |
Dupont |
6 |
16 |
Marc |
7 |
20 |
Lucien |
7 |
20 |
Luc |
SELECT
(SELECT Count(Note)
FROM tbl_note T2
WHERE T2.Note<T1.Note) +1 AS Rang, T1.Note, *
FROM tbl_note AS T1
ORDER BY T1.Note; |
4. Classeement sur deux champs :
Cet exemple tri par note et par nom :
Rang |
Note |
Nom |
1 |
6 |
Henry |
2 |
10 |
Paul |
3 |
12 |
Dupont |
3 |
12 |
Etienne |
3 |
12 |
Simon |
6 |
16 |
Marc |
7 |
20 |
Luc |
7 |
20 |
Lucien |
SELECT
(SELECT Count(Note)
FROM tbl_note T2
WHERE T2.Note<T1.Note) +1 AS Rang, T1.Note, *
FROM tbl_note AS T1
ORDER BY T1.Note,Nom ; |
|
| |
Versions : Access 2000 et supérieures
Cet exemple permet de dupliquer un enregistrement ainsi que ses données sous-jacentes.
Soit les tables suivantes :
- Protocole(IdProtocole,NomProtocole)
- LigneProtocole(IdLigne,LibelleLigne,IdProtocole#)
Les deux clés primaires (soulignées) sont de type Numérotation Automatique.
L'utilisation de DAO va nous permettre de dupliquer le protocole n°1,
de récuperer l'identifiant du nouvel enregistrement
puis ensuite de construire une requête qui recopiera les lignes du protocole.
Pour cela, vous devez ajouter la référence Microsoft DAO à votre projet.
Private Sub Dupliquer()
Dim rstProtocole As DAO.Recordset, rstProtocole2 As DAO.Recordset
Dim Db As DAO.Database, fld As DAO.Field
Dim sql As String
Dim id As Long
Set Db = CurrentDb
Set rstProtocole = Db.OpenRecordset("SELECT NomProtocole FROM Protocole WHERE IdProtocole=1")
If rstProtocole.EOF Then Exit Sub
Set rstProtocole2 = Db.OpenRecordset("protocole")
With rstProtocole2
.AddNew
For Each fld In rstProtocole.Fields
.Fields(fld.Name) = fld.Value
Next
id = .Fields("idprotocole")
.Update
End With
sql = "insert into LigneProtocole (IdProtocole,Libelleligne) SELECT " & _
id & ", LibelleLigne FROM LigneProtocole WHERE idprotocole=1"
Db.Execute sql
End Sub |
|
| |
Versions : Toutes
Objectif : Etablir un calendrier des absences des employés d'une entreprise sans utiliser VBA
Soit la table des absences nommées tblAbsence :
NumEmploye |
DebutAbsence |
FinAbsence |
1 |
10/12/2005 |
13/12/2005 |
2 |
25/12/2005 |
01/01/2006 |
3 |
26/12/2005 |
27/12/2005 |
1 |
04/05/2006 |
07/05/2006 |
On désire obtenir la liste des jours où chaque employé a été absent.
Pour cela 3 tables "outils" sont nécessaires.
- La table tbl_Jours regroupe les numéros des jours : de 0 à 31
- La table tbl_Mois regroupe les mois : de 0 à 12
- La table tbl_Annee regroupe les années utiles : de 2000 à 2010 pour notre exemple
Ainsi, l'ensemble des jours peut être obtenu par une requête nommée R01_Calendrier
SELECT tbl_Jours.Numero & "/" & tbl_Mois.Numero & "/" & tbl_Annee.Numero AS D
FROM tbl_jours, tbl_mois, tbl_annee
WHERE IsDate(tbl_Jours.Numero & "/" & tbl_Mois.Numero & "/" & tbl_Annee.Numero)
ORDER BY tbl_annee.Numero, tbl_Mois.numero, tbl_Jours.numero; |
Enfin, une autre requête nous permet d'obtenir le résultat souhaité
SELECT NumEmploye, D
FROM TblAbsence, R01_Calendrier
WHERE D>=DebutAbsence AND D<=FinAbsence
ORDER BY NumEmploye,D |
NumEmploye |
D |
1 |
10/12/2005 |
1 |
11/12/2005 |
1 |
12/12/2005 |
1 |
13/12/2005 |
1 |
4/5/2006 |
1 |
5/5/2006 |
1 |
6/5/2006 |
1 |
7/5/2006 |
2 |
1/1/2006 |
2 |
25/12/2005 |
2 |
26/12/2005 |
2 |
27/12/2005 |
2 |
28/12/2005 |
2 |
29/12/2005 |
2 |
30/12/2005 |
2 |
31/12/2005 |
3 |
26/12/2005 |
3 |
27/12/2005 |
Un inconvénient majeur est que les produits cartésiens de la première requête ramènent un nombre important de données.
Pour contourner cela, il serait possible de filtrer les années de la
première requête de telle sorte à ne pas générer trop d'enregistrements inutiles.
|
| | Versions : 2000 et supérieures
Ce code permet de rechercher des occurences proches phonétiquement d'un critère. Pour cela, la méthode utilisée est celle de l'algorithme Soundex. Vous en trouverez les origines ici.
Je vous propose donc une traduction de cet algorithme en VBA : Option Compare Database
Option Explicit
Public Function Prepare(Mot As String) As String
Dim I As Integer
Dim Caractere
Mot = Trim$(UCase$(Mot))
For I = 1 To Len(Mot)
Caractere = Mid(Mot, I, 1)
Select Case Asc(Caractere)
Case 192, 194, 196
Prepare = Prepare & "A"
Case 199
Prepare = Prepare & "S"
Case 200 To 203
Prepare = Prepare & "E"
Case 204, 206, 207
Prepare = Prepare & "I"
Case 212, 214
Prepare = Prepare & "O"
Case 217, 219, 220
Prepare = Prepare & "U"
Case Else
If Caractere <> " " & Caractere <> "-" Then _
Prepare = Prepare & Caractere
End Select
Next I
End Function
Public Function Soundex(Mot As String) As String
Dim TLettre() As Variant
Dim I As Integer
Dim Lettre As String
Dim Tmp As String
TLettre = Array("", "1", "2", "3", "", "1", "2", "", "", "2", _
"2", "4", "5", "5", "", "1", "2", "6", "2", "3", _
"", "1", "", "2", "", "2")
Mot = Prepare(Mot)
If Len(Mot) = 0 Then
Soundex = "0000"
Else
If Len(Mot) = 1 Then
Soundex = Mot & "000"
Else
If Left(Mot, 1) = "H" Then Mot = Mid(Mot, 2)
Soundex = Left(Mot, 1)
For I = 2 To Len(Mot)
Lettre = Mid(Mot, I, 1)
If Lettre >= "A" And Lettre <= "Z" Then
Tmp = TLettre(Asc(Lettre) - Asc("A"))
If Tmp <> Right(Soundex, 1) Then Soundex = Soundex & Tmp
End If
Next I
End If
End If
If Len(Soundex) >= 4 Then
Soundex = Left(Soundex, 4)
Else
For I = Len(Soundex) To 3
Soundex = Soundex & "0"
Next I
End If
End Function |
Ainsi, Soundex("Martin") et Soundex("Martan") renvoient la même valeur.
Vous trouverez un exemple d'utilisation complet dans des requêtes SQL en télechargeant le fichier Zip.
|
| |
Version : 2000 et supérieures
Cet exemple traite plusieurs cas, tous basés sur la table suivante (Commande) :
Ref |
Quantite |
Mois |
A1 |
5 |
Juin |
A2 |
10 |
Mai |
A2 |
3 |
Juin |
A4 |
4 |
Aout |
A4 |
4 |
Juin |
A1 |
3 |
Mai |
A1 |
3 |
Mai |
Premier cas
On désire obtenir la somme des produits commandés par mois et par référence ainsi
que la somme total des quantités par produit quelque soit le mois.
Le résultat attendu est donc :
Ref |
Total |
Aout |
Juin |
Mai |
A1 |
11 |
0 |
5 |
6 |
A2 |
13 |
0 |
3 |
10 |
A4 |
8 |
4 |
4 |
0 |
Ce résultat est obtenu par :
TRANSFORM Nz(Sum(Commande.quantite),"0") AS SommeDequantite
SELECT Commande.Ref, Nz(Sum(Commande.quantite),"0") AS Total
FROM Commande
GROUP BY Commande.Ref
PIVOT Commande.mois; |
Deuxième cas
Si l'on souhaite obtenir au contraire la somme des quantités de tous les produits confondus commandés par mois,
il est possible de retourner le tableau, c'est à dire faire figurer les produits en colonne et les mois en ligne.
Mois |
Total de quantité |
A1 |
A2 |
A4 |
Aout |
4 |
0 |
0 |
4 |
Juin |
12 |
5 |
3 |
4 |
Mai |
6 |
6 |
10 |
0 |
Ce résultat est obtenu par :
TRANSFORM Nz(Sum(Commande.quantite),"0") AS SommeDequantite
SELECT Commande.mois, Nz(Sum(Commande.quantite),"0") AS [Total de quantite]
FROM Commande
GROUP BY Commande.mois
PIVOT Commande.Ref; |
Dernier cas
On souhaite obtenir les sommes en colonne et en ligne :
Ref |
Total colonne |
Aout |
Juin |
Mai |
A1 |
8 |
0 |
5 |
3 |
A2 |
13 |
0 |
3 |
10 |
A4 |
8 |
4 |
4 |
0 |
TOTAL |
32 |
4 |
12 |
16 |
Dans ce cas, il nous faut passer par une requête temporaire nommée RTotal
qui va calculer les sommes des colonnes :
SELECT Commande.Ref, Mois, Commande.quantite AS Total,0 as Ordre
FROM Commande
UNION (
SELECT "TOTAL", Mois, sum(Quantite),1 as Ordre FROM Commande GROUP BY Mois,"TOTAL",1); |
Explications :
On utilise une requête Union pour rassembler les lignes de la table commande ainsi que les lignes Total. Le mot
TOTAL sert à considerer le total comme une référence d'un produit. Le champ Ordre va nous
servir à afficher la ligne TOTAL en bas de la liste. Cette requête affiche donc :
Ref |
Mois |
Total |
Ordre |
A1 |
Juin |
5 |
0 |
A1 |
Mai |
3 |
0 |
A2 |
Juin |
3 |
0 |
A2 |
Mai |
10 |
0 |
A4 |
Aout |
4 |
0 |
A4 |
Juin |
4 |
0 |
TOTAL |
Aout |
4 |
1 |
TOTAL |
Juin |
12 |
1 |
TOTAL |
Mai |
16 |
1 |
Ensuite notre requête d'analyse croisée devient :
TRANSFORM Nz(Sum(Rtotal.Total),"0") AS SommeDeTotal
SELECT Rtotal.Ref, Nz(Sum(Rtotal.Total),"0") AS [Total colonne]
FROM Rtotal
GROUP BY Rtotal.Ref, ordre
ORDER BY Ordre
PIVOT Rtotal.Mois; |
Il est important d'appliquer un tri sur le champ Ordre pour afficher la ligne TOTAL en bas. Notons que :
Nous afficherait la ligne TOTAL en haut.
|
| |
Version : Access 2000 et supérieures
Cet exemple d'analyse croisée permet de représenter un tableau à deux dimensions
permettant d'afficher les résultats d'un championnat de tennis.
La table source est nommée tblResultat et possède les données suivantes :
joueur1 |
joueur2 |
setpourjoueur1 |
setcontrejoueur1 |
TOTO |
LULU |
2 |
0 |
DEDE |
JEAN |
2 |
1 |
LULU |
DEDE |
2 |
0 |
JEAN |
TOTO |
0 |
2 |
Avant d'appliquer une requête d'analyse croisée, nous avons besoin d'une première requête nommée RPrepa.
Cette requête va notamment créer les couples JEAN - JEAN, etc ... afin de
différencier les matchs qui ne peuvent pas être joués.
De même la requête dédouble le jeu d'enregistrements en permuttant joueur1 et joueur2.
Le code SQL est le suivant :
SELECT joueur1 as J1,joueur2 AS J2,[setpourjoueur1] as PP,[setcontrejoueur1] as PC
FROM tblResultat
UNION SELECT joueur2 as J1,joueur1 AS J2,[setcontrejoueur1] as PP,[setpourjoueur1] as PC
FROM tblResultat
UNION SELECT DISTINCT joueur1 as J1,joueur1 as J2,"A" as PP,"A" AS PC FROM tblResultat; |
Ce qui renvoie :
J1 |
J2 |
PP |
PC |
DEDE |
DEDE |
A |
A |
DEDE |
JEAN |
2 |
1 |
DEDE |
LULU |
0 |
2 |
JEAN |
DEDE |
1 |
2 |
JEAN |
JEAN |
A |
A |
JEAN |
TOTO |
0 |
2 |
LULU |
DEDE |
2 |
0 |
LULU |
LULU |
A |
A |
LULU |
TOTO |
0 |
2 |
TOTO |
JEAN |
2 |
0 |
TOTO |
LULU |
2 |
0 |
TOTO |
TOTO |
A |
A |
Les matchs non jouables (JEAN-JEAN) possèdent donc un A à la place du résultat.
Enfin, la requête d'analyse croisée rassemble les données :
TRANSFORM IIf(IsNull(First(PP)),"A jouer",
IIF(First(PP)="A","Non Jouable",First(PP) & "-" & First(PC))) AS Resultat
SELECT J1
FROM RPrepa
GROUP BY J1
PIVOT J2; |
Le résultat est alors :
J1 |
DEDE |
JEAN |
LULU |
TOTO |
DEDE |
Non Jouable |
2-1 |
0-2 |
A jouer |
JEAN |
1-2 |
Non Jouable |
A jouer |
0-2 |
LULU |
2-0 |
A jouer |
Non Jouable |
0-2 |
TOTO |
A jouer |
2-0 |
2-0 |
Non Jouable |
|
|