• Aucun résultat trouvé

EXTRACTION DE DONNÉES GROUPÉES

Dans le document BASES DE DONNÉES ET MODÈLES DE CALCUL (Page 107-113)

Le langage SQL DML

5.5 EXTRACTION DE DONNÉES GROUPÉES

© Dunod – La photocopie non autorisée est un délit.

b) Identifiant d’une jointure

Ce que nous venons de discuter conduit à une première règle. L’identifiant du résultat de la jointure :

select * from TA, TB

where TA.IA = TB.RA

est constitué des colonnes de l’identifiant primaire de TB (soit IB). Si certaines colonnes de l’identifiant primaire de TB ne sont pas reprises dans la clause select (et qu’aucun autre identifiant de TB n’est repris), le résultat n’a en principe33 pas d’identifiant, comme on peut l’observer dans la requête suivante, dérivée de celle de la section précédente :

select LOCALITE,LIBELLE

from CLIENT CLI,COMMANDE COM,DETAIL D,PRODUIT P where CLI.NCLI = COM.NCLI

and COM.NCOM = D.NCOM and D.NPRO = P.NPRO

Cette requête représente les détails de commande, mais pour chacun d’eux on ne retient que la localité du client de la commande, ainsi que le libellé de son produit, ce couple de valeurs n’étant évidemment pas identifiant.

L’ajout du modifieur distinct dans la clause select permet de reconstituer un identifiant. Cependant, le résultat serait tout autre : chaque ligne <v,l> de ce résultat représenterait alors le fait que dans la localité v, on a commandé au moins une fois un produit de libellé l.

5.5 EXTRACTION DE DONNÉES GROUPÉES

Les requêtes examinées dans les sections précédentes34 produisent des lignes qui sont généralement en correspondance une pour une avec les lignes d’une table de la clause from. Nous allons examiner comment il est possible d’extraire d’une table, ou d’une jointure, des informations sur des concepts latents dans ces tables.

5.5.1 Notion de groupe de lignes

Considérons la table CLIENT. Il est permis d’y percevoir, virtuellement du moins, des groupes de clients selon leur localité, ou selon leur catégorie, ou encore selon leur nom35. La requête suivante donne, pour chaque groupe de clients classés ou 33. La règle complète est un peu plus complexe. En particulier, si la clé étrangère, même si elle n’est pas (entièrement) reprise dans la clause select, forme un identifiant de TB, et si la clause select reprend un identifiant de TA, alors cet identifiant est aussi celui du résultat de la join-ture.

34. Sauf cas particuliers tels que l’usage de fonctions agrégatives ou du modifieur distinct.

regroupés par localité, le nom de celle-ci, le nombre de clients dans le groupe et le montant moyen des comptes des clients du groupe.

select LOCALITE,

count(*) as NOMBRE_CLIENTS, avg(COMPTE) as MOYENNE_COMPTE from CLIENT

group by LOCALITE

Le résultat compte autant de lignes qu’il y a de groupes ainsi constitués, et donc autant qu’il y a de localités distinctes dans CLIENT :

Nous avons donc interrogé les localités plutôt que les clients. Le mécanisme qui extrait les informations sur les localités à partir des informations sur les clients est invoqué par la clause groupby.

On ne peut trouver dans la clause select que des éléments (colonnes, expression de calcul, fonction agrégatives) définissant une seule valeur par groupe. On n’aurait donc pu y spécifier ni NOM ni CAT. Intuitivement, on ne peut demander à un groupe que des informations communes à tous ses membres : des composants du critère de groupement, des fonctions agrégatives et bien sûr des constantes36.

5.5.2 Sélection de groupes et sélection de lignes

Des conditions de sélection peuvent être imposées aux groupes à sélectionner. Elles seront exprimées dans une clause having, ce qui évite toute confusion avec la clause where qui, elle, s’applique aux lignes. Dans la requête ci-dessous, on ne retient par exemple que les groupes d’au moins trois clients :

select LOCALITE, count(*), avg(COMPTE) from CLIENT

group by LOCALITE having count (*) >= 3 ce qui donne :

35. Les grouper selon leur numéro NCLI constituerait des groupes d’une seule personne, ce qui n’aurait guère d’intérêt.

36. Lorsqu’on interroge un groupe, tous ses membres doivent répondre d’une même voix.

5.5 Extraction de données groupées 109

© Dunod – La photocopie non autorisée est un délit.

Dans cette requête, la condition having peut porter sur les éléments cités dans la clause select, mais aussi sur toute autre fonction d’agrégation calculable sur chaque groupe.

La requête suivante traite les lignes de COMMANDE en les regroupant par client : select NCLI, count(*)

from COMMANDE group by NCLI

On a donc reconstitué des clients à partir des commandes. On ne retient ensuite que les groupes d’au moins deux commandes :

select NCLI, count(*) from COMMANDE

group by NCLI

having count(*) >= 2

Dans le résultat on ne considère ensuite, avant groupement, que les commandes spécifiant le produit PA45. En clair, on s’intéresse aux clients qui ont commandé au moins deux fois le produit PA45 (soit ici l’unique client C400).

select NCLI, count(*)

Il est possible d’obtenir en outre la quantité totale de ce produit PA45 que chaque client a commandée. Les données à afficher appartenant à plusieurs tables (NCLI et somme des QCOM), il nous faut opérer un groupement sur le résultat de la jointure de COMMANDE et DETAIL. On observera que la sous-requête est remplacée par une condition de jointure37.

and NPRO = 'PA45' group by M.NCLI having count(*) >= 2

Selon le même principe de groupement sur une jointure, la requête suivante établit pour chaque client de Poitiers le montant total de ses commandes.

select 'Montant dû par ',C.NCLI,' = ',sum(QCOM*PRIX)

La clause groupby NCLI devrait théoriquement autoriser la présence de NOM ou CAT dans la clause select, puisque par construction à une même valeur de NCLI correspondent toujours la même valeur de NOM et la même valeur de CAT. Il n’en est malheureusement rien, la règle énoncée ci-dessus ne souffrant aucune exception, aussi logique soit-elle. Si nous voulons voir apparaître ces données, alors nous devons écrire group by M.NCLI,NOM,CAT. Pas très élégant, mais efficace !

La requête suivante calcule la quantité qui resterait en stock pour chaque produit si on déduisait les quantités commandées. On observera la présence (en apparence inutile) de QSTOCK dans le critère de groupement réclamée par son apparition dans la clause select en dehors d’une fonction d’agrégation. On observera aussi que seuls les produits effectivement commandés sont repris.

select P.NPRO, QSTOCK - sum(D.QCOM) as SOLDE from DETAIL D, PRODUIT P

where D.NPRO = P.NPRO group by P.NPRO, QSTOCK

5.5.4 Composition du critère de groupement

Nous venons de le voir, le critère de groupement peut inclure plusieurs noms de colonne. L’exemple supplémentaire ci-dessous calcule pour chaque groupe de mêmes valeurs de LOCALITE et NPRO le montant total commandé.

select LOCALITE,P.NPRO,sum(QCOM*PRIX) as Montant from CLIENT C, COMMANDE M, DETAIL D, PRODUIT P

5.5 Extraction de données groupées 111

© Dunod – La photocopie non autorisée est un délit.

and M.NCOM = D.NCOM and D.NPRO = P.NPRO group by LOCALITE, P.NPRO

L’ordre des composants est indifférent : groupbyP.NPRO,LOCALITE donnerait le même résultat.

Le critère de groupement peut aussi inclure une expression de calcul quelconque.

La requête suivante constitue des groupes de clients selon la première lettre de leur valeur de CAT.

select substring(CAT from 1 for 1) as CAT, count(*) as N from CLIENT

group by substring(CAT from 1 for 1)

Il est évident que certains critères de groupement sont plus pertinents que d’autres.

Par exemple, un groupement sur les valeurs COMPTE serait sans intérêt. En revanche, il serait très intéressant de regrouper les clients selon leurs valeurs de COMPTE par intervalles de 1.000, comme dans la requête ci-dessous.

select "de ", int(COMPTE/1000)*1000 as Min,

" à ", int(COMPTE/1000)*1000 + 999 as Max, count(*) as N

from CLIENT C

group by int(COMPTE/1000)

5.5.5 Attention aux groupements multi-niveaux

L’extraction de données groupées est à définir avec précaution en présence de join-tures. Cherchons par exemple à déterminer, pour chaque localité, la somme des comptes des clients et le nombre de commandes. On serait tenté d’écrire :

select LOCALITE, sum(COMPTE), count(*) from CLIENT C, COMMANDE M

ce qui nous donnerait :

Ce résultat, en apparence correct, est pourtant erroné (indépendamment du fait que les clients sans commandes ne sont pas repris). En effet, le résultat de la jointure représente des commandes et non des clients. En particulier, le compte du client C400 est compté trois fois, pour un total de 1050 au lieu de 350. Le calcul de la somme des comptes se fait donc sur des ensembles de commandes et non de clients.

Tout client qui possède plus d’une commande verra son compte intervenir plus d’une fois dans la somme. En revanche, le comptage des commandes par localité est correct. Il faudra, pour répondre à la question posée, procéder en deux étapes indé-pendantes.

Dans certains cas cependant, il est possible de citer des fonctions agrégatives à plusieurs niveaux, pour autant que toutes les fonctions sommatives (sum et avg) s’adressent au niveau le plus bas des jointures, les fonctions count, max et min pouvant s’appliquer à tous les niveaux. La requête ci-dessous illustre cette structure.

Elle recherche, pour chaque client, le nombre de commandes et le montant total de ces commandes. La première information est relative au niveau COMMANDE tandis que la seconde dérive du niveau DETAIL. Pour obtenir le nombre exact de commandes, on utilisera le modifieur distinct dans la fonction count.

select M.NCLI,count(distinct M.NCOM),sum(QCOM*PRIX) from COMMANDE M, DETAIL D, PRODUIT P

where M.NCOM = D.NCOM and D.NPRO = P.NPRO group by M.NCLI

5.5.6 Peut-on éviter l’utilisation de données groupées ?

Il est possible d’éviter la clause groupby lorsque le concept latent dans une table est explicitement représenté par une autre table, et que le regroupement ne sert qu’à la sélection. On recherche par exemple les produits dont on a commandé plus de 500 unités en 2005. La forme qui semble s’imposer est la suivante, qui extrait les produits comme concept latent de la table DETAIL, via la colonne NPRO :

select D.NPRO

Dans le document BASES DE DONNÉES ET MODÈLES DE CALCUL (Page 107-113)