Top 11 à 15 avec regroupement

Suite au billet précédent, on souhaite obtenir le TOP 11 à 15 des Id (par ordre croissant) liés à chaque personne.

Création de la table et insertion des données
La structure de la table est un peu différente du billet précédent pour visualiser facilement la sélection de la requête :

Public Function CreationTableTop2()
   Const cInsert As String = "INSERT INTO tTop2 (Id, Nom) VALUES "
   Dim i As Long, j As Long
   Dim aNoms As Variant
 
   With DoCmd
      .SetWarnings False
 
      .RunSQL "CREATE TABLE tTop2 (Id LONG, Nom CHAR, " & _
              "CONSTRAINT PrimaryKey PRIMARY KEY(Id, Nom));"
 
      aNoms = Array("Albert", "Marcel", "Bernard", "Dominique")
 
      For i = LBound(aNoms) To UBound(aNoms)
         For j = 1 To 25
            .RunSQL cInsert & "(" & j & ",'" & aNoms(i) & "');"
         Next j
      Next i
 
      .SetWarnings True
   End With
   MsgBox "Création terminée"
End Function

 
Résultat attendu

Id Nom
11 Albert
12 Albert
13 Albert
14 Albert
15 Albert
11 Bernard
12 Bernard
…

 
La requête SQL
Une solution possible est :


SELECT *
FROM   ttop2 AS T1
WHERE  id > ALL (SELECT TOP 10 id
                
FROM   ttop2 T
                
WHERE  T.nom = T1.nom
                
ORDER  BY id)
       AND
id <= ANY (SELECT TOP 15 id
                      
FROM   ttop2 T
                      
WHERE  T.nom = T1.nom
                      
ORDER  BY id)
ORDER  BY nom,
          
id

 
Explications
La clause Where va filtrer les lignes sur deux critères complémentaires :
Toutes les lignes retournées doivent avoir un Id > à tous les Id du TOP 10 du même NOM ET un Id <= à au moins un Id du TOP 15 du même NOM.
Finalement, seules les Id du TOP 11 à 15 répondent aux deux critères et les lignes correspondantes sont retournées.

Autre solution
Il est possible de substituer >ALL et <=Any par Not In et In :

SELECT *
    
FROM tTop2 AS T1
    
WHERE id NOT IN  (
    
SELECT TOP 10 Id
        
FROM tTop2 T
        
WHERE T.Nom=T1.Nom
        
ORDER BY Id)
        AND
id IN (
    
SELECT TOP 15 Id
        
FROM tTop2 T
        
WHERE T.Nom=T1.Nom
        
ORDER BY Id)
    
ORDER BY Nom, id;
 

Performance
Il est recommandé d’indexer sans doublons la colonne ‘Nom’ sur laquelle porte la clause Where.
Compte-tenu de la présence de 2 sous-requêtes, cette requête est adaptée pour une table possédant moins de 1000 lignes…

Si vous avez d’autres solutions, n’hésitez pas à les placer en commentaire.

@+

Philippe

Laisser un commentaire