• Aucun résultat trouvé

Attention aux conditions d’association négatives

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

Le langage SQL DML

5.3 SÉLECTION UTILISANT PLUSIEURS TABLES : LES SOUS-REQUÊTES

5.3.3 Attention aux conditions d’association négatives

a) Le problème

La requête suivante désigne les commandes (c’est-à-dire les lignes de la table COMMANDE) qui ne spécifient pas le produit PA60, autrement dit, celles pour lesquelles il n’existe aucun détail spécifiant PA60.

Q1: select NCOM, DATECOM, NCLI from COMMANDE

where NCOM not in ( select NCOM from DETAIL

where NPRO = 'PA60')

La sous-requête (select NCOM from DETAIL where NPRO = 'PA60') désigne ici les numéros des commandes dont au moins un détail spécifie le produit PA60. La commande qui contient un de ces détails est donc à rejeter (not in).

Contrairement aux requêtes précédentes, on retient les lignes qui ne sont pas asso-ciées aux éléments d’un ensemble déterminé de lignes.

La requête suivante est parfois proposée, à tort, comme autre solution à ce problème. En fait, cette requête désigne les commandes qui spécifient au moins un produit différent de PA60 (mais qui par ailleurs peuvent également spécifier le produit PA60!).

Q2: select NCOM, DATECOM, NCLI from COMMANDE

where NCOM in ( select NCOM from DETAIL

where NPRO <> 'PA60')

Ces deux requêtes, qui sont basées sur des conditions de sélection négatives, doivent être examinées soigneusement car ces dernières sont la source d’erreurs fréquentes. On analysera en particulier le résultat à obtenir sur la base de la parti-tion16 suivante de l’ensemble des commandes (figure 5.1) :

• C1 : les commandes qui n’ont pas de détails (cas rare !),

• C2 : les commandes dont aucun détail ne spécifie PA60,

• C3 : les commandes ayant à la fois un détail spécifiant PA60 et au moins un détail spécifiant un autre produit,

• C4 : les commandes ne spécifiant que PA60.

16. On rappelle que l’ensemble de sous-ensembles non vides {E1, E2,..., En}, pour n>1, forme une partition de E, non vide, ssi, (E = E1E2...En) et ( i,j [1..n], ij Ei Ej = ).

5.3 Sélection utilisant plusieurs tables : les sous-requêtes 85

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

Figure 5.1 - Une partition de l’ensemble des commandes explicitant la portée des requêtes Q1 et Q2. Dans un souci de généralité, on admet qu’une commande puisse n’avoir aucun détail

La première requête correspond aux catégories C1 et C2, tandis que la seconde correspond aux catégories C2 et C3.

b) Méthode générale

D’une manière générale, on traitera ce type de requêtes de la manière suivante.

1. On identifie les deux ensembles de lignes A et B tels que la partie critique de la requête puisse se paraphraser sous la forme on sélectionne les A qui ne sont pas associés à des B.

2. On repère les tables et les conditions de sélection qui définissent A et B, soient TAwhere(CA) et TBwhere(CB).

3. On repère dans TA et TB les colonnes FA et FB constituant l’identifiant et la clé étrangère dont l’égalité matérialise l’association.

4. On peut alors construire la requête sous la forme : from TA

where (CA)

and FA not in (select FB from TB where (CB))

Appliquons cette procédure à un autre exemple : sélectionner les clients de Poitiers qui n’ont pas commandé en 2005.

1. Les deux ensembles sont A = {les clients de Poitiers} et B = {les commandes de 2005}.

2. Ils s’expriment respectivement par "CLIENT where LOCALITE = ’Poitiers’"

et "COMMANDE where DATECOM like ’%2005’".

3. Les colonnes en correspondance sont respectivement NCLI dans CLIENT et NCLI dans COMMANDE.

4. D’où la requête : from CLIENT

where LOCALITE = 'POITIERS' and NCLI not in (select NCLI from COMMANDE

where DATECOM like '%2005') 5.3.4 Références multiples à une même table

a) Premiers exemples

Une sous-requête peut être définie sur la même table que la requête qui la contient.

La requête suivante répond à la question : Quels sont les clients qui habitent dans la même localité17 que le client n° B512?

select *

from CLIENT

where LOCALITE in ( select LOCALITE from CLIENT

where NCLI = 'B512')

La requête ci-dessous recherche les commandes qui spécifient une quantité du produit PA60 inférieure à celle que spécifie la commande 30182 pour ce même produit.

select *

from COMMANDE

where NCOM in (select NCOM from DETAIL

where NPRO = 'PA60'

and QCOM < (select QCOM from DETAIL

where NPRO = 'PA60' and NCOM = '30182')) Il n’y a ici aucune confusion possible quant à savoir à quelle ligne de DETAIL font référence les noms NPRO et NCOM de la deuxième sous-requête. La règle est qu’ils sont relatifs à la requête la plus emboîtée dont la table contient une colonne de ce nom. On notera la double apparition de la condition NPRO = PA60. Pourquoi ?

On peut forcer cette règle de deux manières :

• si deux tables ont deux colonnes de même nom, on pourra préfixer le nom de la colonne du nom de la table. On écrira par exemple COMMANDE.NCLI et CLIENT.NCLI afin de distinguer les deux colonnes de nom NCLI dans le schéma;

17. On notera que le client B512 apparaît dans le résultat. On pourrait l’en exclure aisément.

Comment ?

5.3 Sélection utilisant plusieurs tables : les sous-requêtes 87

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

• on peut également attribuer un synonyme, dit alias de table, à un nom de table apparaissant dans une clause from. Si nécessaire, on qualifiera le nom de colonne de ce synonyme. Le terme as est facultatif, et sera omis à l’occasion.

select *

from PRODUIT as P1 where P1.PRIX > 123

b) Les sous-requêtes corrélées

Dans certaines formes, l’alias de table est utilisé pour établir une corrélation entre la requête principale et une sous-requête. A titre d’illustration, exprimons la requête suivante : sélectionner les clients dont le compte est supérieur à la moyenne des comptes des clients de la même commune.

select NCLI, NOM, LOCALITE, COMPTE

c) Extension des opérateurs de comparaison

Si la sous-requête renvoie une seule ligne, il est permis d’utiliser les opérateurs de comparaison classiques :

select *

from CLIENT

where COMPTE > ( select COMPTE

from CLIENT where NCLI = 'C400') De même, l’opérateur "in" pourra s’écrire "=" et "notin" s’écrira aussi "<>".

18. Cette clause, qui peut être ignorée, sera expliquée plus tard.

NCLI NOM LOCALITE COMPTE

d) Conditions d’association quantifiées

Il est intéressant de sélectionner les lignes d’une table qui sont associées, non pas à au moins une des lignes d’une autre table qui vérifient une certaine condition, mais bien à un nombre défini de ces lignes. La requête suivante recherche les commandes d’au moins 3 détails.

select NCOM, DATECOM, NCLI from COMMANDE C

where (select count(*) from DETAIL

where NCOM = C.NCOM) >= 3 e) Null = null ?

C’est l’occasion d’examiner d’un peu plus près les moeurs sociales de la valeur null. De manière assez surprenante, la requête :

select NCLI from CLIENT where CAT in ( select CAT from CLIENT

where NCLI = 'D063')

. . . renvoie une réponse vide, alors que celle-ci devrait au moins contenir la réfé-rence D063 ! La raison en est très simple : la valeur de CAT du client D063 est null, or null n’est en principe comparable à rien, même pas à lui-même19, puisqu’il est généralement interprété comme inconnu. Nous rediscuterons de cette question plus tard (section 6.10).

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