IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo
Sommaire > Requêtes
        Concaténer plusieurs enregistrements dans une seule colonne
        Classer des données par plage
        Classer les résultats d'une requête
        Dupliquer des enregistrements en cascade
        Générer un calendrier
        Effectuer des recherches phonétiques
        Réaliser des totaux en ligne et en colonne
        Réaliser un tableau de score

rechercher
precedent    sommaire    suivant    telecharger


Auteur : Tofalu
Version : 05/03/2005
Page de l'auteur
Concaténer plusieurs enregistrements dans une seule colonne
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
'Selectionne les participant du projet
SQL = "SELECT NomParticipant FROM Tbl_Projet WHERE Projet=" & Projet
Set res = CurrentDb.OpenRecordset(SQL)
'Concatene les différents enregistrement
While Not res.EOF
RecupParticipant = RecupParticipant & res.Fields(0).Value & " "
res.MoveNext
Wend
'Enleve le dernier espace
RecupParticipant = Left(RecupParticipant, Len(RecupParticipant) - 1)
'libere la mémoire
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
'Selectionne les  projet du partcipant
'chr(34) correspond a des guillemets pour encadrer le texte
SQL = "SELECT Projet FROM Tbl_Projet WHERE NomParticipant=" & _
          Chr(34) & Nom & Chr(34)
Set res = CurrentDb.OpenRecordset(SQL)
'Concatene les différents enregistrement
While Not res.EOF
RecupProjet = RecupProjet & res.Fields(0).Value & ";"
res.MoveNext
Wend
'Enleve le dernier ;
RecupProjet = Left(RecupProjet, Len(RecupProjet) - 1)
'libere la mémoire
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;

Auteur : Maxence Hubiche
Version : 08/07/2005
Classer des données par plage
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

Auteur : Tofalu
Version : 05/03/2005
Page de l'auteur
Classer les résultats d'une requête
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 ;

Auteur : Tofalu
Version : 12/11/2005
Page de l'auteur
Dupliquer des enregistrements en cascade
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 
'Ouvre le recordset où sera prélevé le protocole 
Set rstProtocole = Db.OpenRecordset("SELECT NomProtocole FROM Protocole WHERE IdProtocole=1") 
'Verifie que le protocole 1 existe 
If rstProtocole.EOF Then Exit Sub 
'ouvre le recordset où sera ajouté le protocole 
Set rstProtocole2 = Db.OpenRecordset("protocole") 
'Duplique le protocole 
With rstProtocole2 
  .AddNew 
  'duplique les champs 
  For Each fld In rstProtocole.Fields 
    .Fields(fld.Name) = fld.Value 
  Next 
  id = .Fields("idprotocole") 
  .Update 
  'se positionne sur l'enregistrement ajouté 
End With 

'Duplique les lignes 
sql = "insert into LigneProtocole (IdProtocole,Libelleligne) SELECT " & _
  id & ", LibelleLigne FROM LigneProtocole WHERE idprotocole=1" 
Db.Execute sql 
End Sub

Auteur : Tofalu
Version : 12/11/2005
Page de l'auteur
Générer un calendrier
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.


Auteur : Tofalu
Version : 05/03/2005
Page de l'auteur
Téléchargez le zip
Effectuer des recherches phonétiques
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
'Cette fonction est inspirée de :
'http://sqlpro.developpez.com/cours/soundex/
'On enleve les espaces et convertit en majuscule
Dim I As Integer
Dim Caractere
Mot = Trim$(UCase$(Mot))
'On convertit les caractères accentués
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
'Tableau de correspondance
TLettre = Array("", "1", "2", "3", "", "1", "2", "", "", "2", _
            "2", "4", "5", "5", "", "1", "2", "6", "2", "3", _
            "", "1", "", "2", "", "2")
Mot = Prepare(Mot)
'cas particulier de chaine vide
If Len(Mot) = 0 Then
  Soundex = "0000"
Else
  'cas particulier de chaine à 1 caractère
  If Len(Mot) = 1 Then
    Soundex = Mot & "000"
  Else
  'Enleve le H (si présent) au début
  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)
    'Transcode
    If Lettre >= "A" And Lettre <= "Z" Then
      Tmp = TLettre(Asc(Lettre) - Asc("A"))
      'Evite les doublons
      If Tmp <> Right(Soundex, 1) Then Soundex = Soundex & Tmp
    End If
  Next I
  End If
End If
'on recupère les 4 premiers
If Len(Soundex) >= 4 Then
  Soundex = Left(Soundex, 4)
Else
'sinon on complete
  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.


Auteur : Tofalu
Version : 20/05/2005
Page de l'auteur
Réaliser des totaux en ligne et en colonne
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 :
ORDER BY Ordre DESC
Nous afficherait la ligne TOTAL en haut.


Auteur : Tofalu
Version : 20/05/2005
Page de l'auteur
Réaliser un tableau de score
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

rechercher
precedent    sommaire    suivant    telecharger

Valid XHTML 1.1!Valid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2005 Maxence Hubiche Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.