diff --git a/Jointure.md b/Jointure.md index cff9ac5..bd718a9 100644 --- a/Jointure.md +++ b/Jointure.md @@ -101,12 +101,13 @@ WHERE gauche IS NULL; ``` ![](jointures/rightantijoin.svg) -Lister les articles dont la famille n'existe pas. +**Exercice :** Lister les articles dont la famille n'existe pas. ```sql select * from article left join famille on famille.code = article.famille_code where famille.code is null +>> MENMA Plant Menthe Pomme ``` Attention ! La valeur `null` ne peut être comparée à rien. L'égalité avec null retourne ni vrai ni faux mais null. Ainsi null n'est pas égal à null. Pour la comparaison avec null il faut utiliser les mots-clés `is` ou `is not`. @@ -198,6 +199,7 @@ Avantages : - Robuste face aux valeurs NULL (pas d’ambiguïté). - Souvent optimisé par le moteur en anti-semi-join (c’est-à-dire que le moteur ne lit pas plus de lignes que nécessaire dans la table de droite). Les jointures qui passent par des produits cartésiens sont consommatrices en ressources. +**Exercice :** Lister les articles dont la famille n'existe pas. ```sql select * from article @@ -207,6 +209,8 @@ where not exists ( ) ``` +Ou avec l'opérateur `not in` + ```sql select * from article where famille_code not in ( @@ -215,7 +219,7 @@ where famille_code not in ( ) ``` -Cette requête est elle aussi équivalente cependant il existe un risque de mauvaise interprétation. Si le sous-select contient au moins un NULL, alors toutes les lignes sont rejetées (car la comparaison avec la valeur NULL dans id NOT IN ( …, NULL, … ) est indéterminée.) +Cette requête est elle aussi équivalente cependant il existe un risque de mauvaise interprétation. Si le sous-select contient au moins un NULL, alors toutes les lignes sont rejetées (car la comparaison avec la valeur NULL dans code NOT IN ( …, NULL, … ) est indéterminée.) Il existe plusieurs syntaxes permettant d’obtenir le même résultat. Toutefois, certains points méritent d’être pris en compte : - **Consommation de ressources** : un même résultat peut être produit par des requêtes dont le coût en temps d’exécution ou en mémoire diffère sensiblement. diff --git a/aggregation.md b/aggregation.md index 6e563f2..1caa656 100644 --- a/aggregation.md +++ b/aggregation.md @@ -15,9 +15,21 @@ select count(*) from adherent On peut compter sur n'importe quelle colonne, dans ce cas, pour ne pas avoir à choisir on utilise le caractère joker *. +**Exercice :** Compter le nombre d'articles de la famille 02CHOU. + +```sql +select count(*) from article + where famille_code = '02CHOU' +>> 29 +``` + ### distinct -En ajoutant le mot clé `distinct` l'opération s'effectue sur les **valeurs uniques** d'une ou de plusieurs colonnes. +En ajoutant le mot clé `distinct` l'opération s'effectue sur les **valeurs uniques** d'une ou de plusieurs colonnes.select codepostal, + count(case when genre = 1 then 1 end) as nb_hommes, + count(case when genre = 2 then 1 end) as nb_femmes +from adherent +group by codepostal; **Exercice :** Afficher le nombre de codes postaux différents trouvés dans la table adhérent. diff --git a/sousrequete.md b/sousrequete.md index 2a53019..8a3aa3e 100644 --- a/sousrequete.md +++ b/sousrequete.md @@ -18,13 +18,44 @@ Parce qu’elle doit produire une table (un jeu de résultats) indépendante **a - Dans le SELECT, une sous-requête peut être corrélée (elle utilise des colonnes de la requête principale) ou non. - Dans le WHERE, idem : elle peut être corrélée (EXISTS, IN dépendant de la ligne en cours) ou non (test fixe). +**Exercice : ** Sélectionner les articles dont le prix est supérieur à la moyenne générale des prix des articles. + +Dans un langage procédural on utiliserait deux étapes pour obtenir le résultat. Première étape calculer la moyenne des prix + ```sql -select * from article a1 where prix > ( - select avg(prix) from article - where famille_code = a1.famille_code -) +select avg(prix) from article +>> 5.8060418562329390 ``` +Puis dans un deuxième temps faire la requête de sélection avec la valeur trouvée. + +```sql +select * from article where prix > 5.8060418562329390 +``` + +Il est possible d'utiliser une sous requête à l'intérieur de la requête principale. La sous requête calcule la moyenne à l'endroit nécessaire. + +```sql +select * from article + where prix > (select avg(prix) from article); +``` + +**Exercice : ** Sélectionner les articles dont le prix est supérieur à la moyenne des prix des articles de la même famille. + +Cette fois ci il faut calculer les moyennes des prix pour chacune des familles et comparer les articles avec la moyenne correspondante. Ce n'est plus possible en programmation procédurale. + +La sous requête permet de calculer pour chaque ligne d'article la moyenne correspondante à la famille du dit article. + +```sql +select code, article, prix from article a1 + where prix > ( + select avg(prix) from article + where famille_code = a1.famille_code + ) +``` + +Remarquez l'utilisation de l'alias `a1` sur la table de la requête principale pour pouvoir être injecter sans confusion dans la sous requête car celle-ci utilise la même table. + ## Sous-requête scalaire > une sous-requête scalaire est une sous-requête qui retourne **une seule valeur** (un scalaire, c’est-à-dire une seule ligne et une seule colonne). diff --git a/window.md b/window.md index 4ee9aeb..02e71c5 100644 --- a/window.md +++ b/window.md @@ -129,6 +129,16 @@ ORDER BY est obligatoire lorsque LEAD() est utilisé. La séquence des lignes do column_2 est la colonne qui défini l'ordre des lignes lors de la récupération de la valeur suivante. Vous pouvez spécifier plus d'une colonne. +**Exercice :** Afficher le chiffre d'affaire mensuel pour chaque mois, puis dans une deuxième colonne le chiffre d'affaire du mois précédent + +```sql +select * , + lag(total) over (order by mois) as total_mois_p, + total - lag(total) over (order by mois) as difference, + lag(total, 12) over (order by mois) as total_annee_p +from ca_mensuel +order by mois +``` #### première valeur