sous requetes

2025-08-30 09:45:49 +02:00
parent 03456a364b
commit ee87e2970a
6 changed files with 197 additions and 14 deletions

@@ -2,5 +2,6 @@
- [Fonctions d'agrégation](aggregation.md) - [Fonctions d'agrégation](aggregation.md)
- [Jointure](Jointures.md) - [Jointure](Jointures.md)
- [Sous requêtes](sousrequete.md)
- [Arbres](Arbres.md) - [Arbres](Arbres.md)
- [Fonctions de fenêtrage](window.md) - [Fonctions de fenêtrage](window.md)

@@ -46,7 +46,7 @@ ON gauche.id = droite.id;
## Jointure externe complète ## Jointure externe complète
`FULL JOIN` ou `FULL OUTER JOIN` combine les fonctionnalités des jointures gauche et droite. Elle renvoie toutes les lignes des deux tables, avec des valeurs NULL là où il n'y a pas de correspondance dans l'autre table. `FULL JOIN` ou `FULL OUTER JOIN` combine les fonctionnalités des jointures gauche et droite. Elle renvoie toutes les lignes des deux tables, avec des valeurs NULL là où il n'y a pas de correspondance dans l'autre table. Toutes les lignes des deux tables sont conservées, quil y ait correspondance ou pas.
```sql ```sql
SELECT gauche.colonne, droite.colonne SELECT gauche.colonne, droite.colonne
@@ -57,6 +57,24 @@ ON gauche.id = droite.id;
![](jointures/fullouterjoin.svg) ![](jointures/fullouterjoin.svg)
Le fait davoir des NULL des deux côtés est le cœur de lintérêt du FULL OUTER JOIN :
Cela permet dobtenir tous les enregistrements présents dans lune ou lautre table, même quand il nexiste aucune intersection.
Utile pour comparer des ensembles de données et voir ce qui est :
- présent uniquement à gauche,
- présent uniquement à droite,
- présent dans les deux.
C'est jointure est utilisée pour:
- des comparaisons dinventaires (ex. produits dun magasin vs produits dun fournisseur).
- la synchronisation de données (trouver ce qui manque dun côté ou de lautre).
- de l'audit de cohérence (détecter des écarts entre deux tables censées contenir la même information).
![](jointures/fullantijoin.svg)
## Jointure d'exclusion ## Jointure d'exclusion
Un jointure d'exclusion à gauche (left anti-join) garde uniquement les lignes pour lesquelles il ny a **pas** de correspondance (cest-à-dire que les colonnes de la table de droite sont NULL). Un jointure d'exclusion à gauche (left anti-join) garde uniquement les lignes pour lesquelles il ny a **pas** de correspondance (cest-à-dire que les colonnes de la table de droite sont NULL).
@@ -95,6 +113,43 @@ CROSS JOIN droite;
Cela peut être utile dans des situations spécifiques mais doit être utilisé avec prudence car cela peut générer des résultats volumineux. Cela peut être utile dans des situations spécifiques mais doit être utilisé avec prudence car cela peut générer des résultats volumineux.
Table `Gauche` (3 lignes) :
| id | couleur |
| -- | ------- |
| 1 | Rouge |
| 2 | Vert |
| 3 | Bleu |
Table `Droite` (2 lignes) :
| taille |
| ------ |
| M |
| XL |
Résultat (3 × 2 = 6 lignes) :
| id | couleur | taille |
| -- | ----- | ---- |
| 1 | Rouge | M |
| 1 | Rouge | XL |
| 2 | Vert | M |
| 2 | Vert | XL |
| 3 | Bleu | M |
| 3 | Bleu | XL |
## Jointure naturelle
La jointure naturelle ne spécifie pas la ou les colonnes de jointure. Cette jointure seffectue à la condition quil y ai des colonnes de même nom et de même type dans les 2 tables.
```sql
SELECT *
FROM gauche
NATURAL JOIN droite
```
## Ancienne syntaxe ## Ancienne syntaxe
L'ancienne syntaxe qui date de 1992 n'utilise pas les mots clés `JOIN` mais liste uniquement les tables dans la clause `FROM`. L'ancienne syntaxe qui date de 1992 n'utilise pas les mots clés `JOIN` mais liste uniquement les tables dans la clause `FROM`.
@@ -112,7 +167,7 @@ FROM A, B
WHERE A.id = B.a_id; WHERE A.id = B.a_id;
``` ```
## EXISTS ## Alternatives
Les jointures d'exclusion peuvent aussi s'écrire avec une sous requête et une condition `EXISTS`. Les jointures d'exclusion peuvent aussi s'écrire avec une sous requête et une condition `EXISTS`.
@@ -132,10 +187,6 @@ Avantages :
- Robuste face aux valeurs NULL (pas dambiguïté). - Robuste face aux valeurs NULL (pas dambiguïté).
- Souvent optimisé par le moteur en anti-semi-join (cest-à-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. - Souvent optimisé par le moteur en anti-semi-join (cest-à-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.
Il existe plusieurs syntaxes permettant dobtenir 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 dexécution ou en mémoire diffère sensiblement.
- **Lisibilité** : les syntaxes modernes apportent plus de clarté et facilitent la compréhension de lintention de la requête.
```sql ```sql
SELECT g.* SELECT g.*
FROM gauche g FROM gauche g
@@ -147,16 +198,21 @@ WHERE g.id 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 id NOT IN ( …, NULL, … ) est indéterminée.)
## Self Join (auto-jointure) Il existe plusieurs syntaxes permettant dobtenir 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 dexécution ou en mémoire diffère sensiblement.
- **Lisibilité** : les syntaxes modernes apportent plus de clarté et facilitent la compréhension de lintention de la requête.
C'est une jointure dans laquelle une table est jointe avec elle-même. Cela peut être utile pour comparer les lignes d'une même table. Des alias sont utilisés pour identifier la partie gauche de la partie droite ## Auto-jointure
C'est une jointure dans laquelle une table est jointe avec elle-même (self join). Cela peut être utile pour comparer les lignes d'une même table. Comme la table apparaît deux fois dans la requête, des alias sont utilisés pour identifier la partie gauche de la partie droite
```sql ```sql
SELECT G.colonne, D.colonne SELECT G.colonne, D.colonne
FROM table G, table D FROM table G
WHERE G.nom = D.nom; JOIN table D ON G.nom = D.nom
WHERE G.id <> D.id;
``` ```
![SQL Jointure](jointures/SQL_Joins.svg)
C'est une représentation purement théorique il n'y a pas de mot clé particulier, la différence est seulement que la même table apparaît plusieurs fois.
## lateral Ce type de requête est utilisées pour comparer des lignes entres elles ou détecter des doublons.

@@ -1,13 +1,15 @@
-- ---------- -- ----------
-- Combien d'adhérents nont jamais acheté d'article ? -- 1a Combien d'adhérents nont jamais acheté d'article ?
-- 273
SELECT COUNT(*) AS nb_adherents_sans_achat SELECT COUNT(*) AS nb_adherents_sans_achat
FROM adherent a FROM adherent a
LEFT JOIN ticket t ON t.adherent_id = a.id LEFT JOIN ticket t ON t.adherent_id = a.id
LEFT JOIN ligne l ON l.ticket_id = t.id LEFT JOIN ligne l ON l.ticket_id = t.id
WHERE l.id IS NULL; WHERE l.id IS NULL;
-- 1b : Combien d'adhérents nont aucun ticket ?
SELECT COUNT(*) AS nb_adherents_sans_achat SELECT COUNT(*) AS nb_adherents_sans_achat
FROM adherent a FROM adherent a
WHERE NOT EXISTS ( WHERE NOT EXISTS (
@@ -17,6 +19,32 @@ WHERE NOT EXISTS (
WHERE t.adherent_id = a.id WHERE t.adherent_id = a.id
); );
-- 1c Combien de tickets sont vides (sans ligne)
SELECT t.*
FROM ticket t
LEFT JOIN ligne l ON l.ticket_id = t.id
WHERE l.id IS NULL;
-- 2a Quel est l'article qui n'a jamais été commandé
SELECT a.code, a.article, a.famille_code, a.prix
FROM article a
WHERE NOT EXISTS (
SELECT 1
FROM ligne l
WHERE l.article_code = a.code
);
-- 2b
SELECT a.code, a.article, a.famille_code
FROM article a
JOIN ligne l ON l.article_code = a.code
GROUP BY a.code
HAVING COUNT(*) = 1;
-- 3 Lister les articles dont la famille est absente
select a.* from article a
left join famille f on f.code = a.famille_code
where f.code is null
-- Combien d'adhérents nont aucun ticket ? -- Combien d'adhérents nont aucun ticket ?

@@ -10,7 +10,7 @@ Compte le nombre d'enregistrements dans un ensemble de données.
SELECT COUNT(*) FROM utilisateurs; SELECT COUNT(*) FROM utilisateurs;
``` ```
On peut compter sur n'importe quelle colonne, dans ce cas pour ne pas avoir à choisir on utilise le caractère joker *. On peut compter sur n'importe quelle colonne, dans ce cas, pour ne pas avoir à choisir on utilise le caractère joker *.
### Somme ### Somme

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" width="400" height="300" viewBox="0 0 800 600" version="1.1">
<g style="stroke:#000000;stroke-width:4">
<path style="fill:#fff;" d="m 348.5301,292.16164 c 0,-54.25306 21.33532,-103.52299 56.13833,-139.99391 34.93487,36.25996 56.36165,85.62469 56.36165,139.99391 0,54.20576 -21.29814,103.43708 -56.02381,140.01839 C 370.01352,396.02597 348.5301,346.60266 348.5301,292.16164 z"/>
<path style="fill:#f00;" d="m 550.44376,494.66164 c 111.83766,0 202.5,-90.66234 202.5,-202.5 0,-111.83766 -90.66234,-202.500004 -202.5,-202.500004 -57.5846,0 -109.55528,24.036074 -146.36166,62.506094 34.93488,36.25996 56.36166,85.62469 56.36166,139.99391 0,54.20576 -21.29814,103.43708 -56.02382,140.01839 36.80788,38.6022 88.62718,62.48161 146.02382,62.48161 z"/>
<path style="fill:#f00;" d="m 258.5821,494.66164 c -111.83766,0 -202.5,-90.66234 -202.5,-202.5 0,-111.83766 90.66234,-202.500004 202.5,-202.500004 57.5846,0 109.55528,24.036074 146.36166,62.506094 -34.93488,36.25996 -56.36166,85.62469 -56.36166,139.99391 0,54.20576 21.29814,103.43708 56.02382,140.01839 -36.80788,38.6022 -88.62718,62.48161 -146.02382,62.48161 z" />
</g>
<g>
<text y="312.31482" x="235.67825" style="font-size:120px;font-family:Sans"><tspan y="312" x="210">G</tspan></text>
<text y="312.31482" x="531.66656" style="font-size:120px;font-family:Sans"><tspan y="312" x="530">D</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

86
sousrequete.md Normal file

@@ -0,0 +1,86 @@
# Sous requête
Une sous-requête (subquery) est une requête SQL placée à lintérieur dune autre requête.
Elle est généralement entourée de parenthèses avec un nom d'alias et peut apparaître dans
- la clause WHERE
- la clause FROM (on parle alors de table dérivée)
- la clause SELECT
- parfois dans HAVING
Il existe deux types de sous requêtes :
- La sous-requête corrélée qui dépend de la requête principale. Elle est donc réévaluée pour chaque ligne.
- La sous-requête non corréléé qui est indépendante et exécuté une seule fois.
## Valeur
Une sous requête renvoie un ensemble de valeurs. Il est possible de renvoyer une seule valeur en limitant les résultats.
```sql
SELECT *
FROM table
WHERE nom_colonne = (
SELECT valeur
FROM table2
LIMIT 1
)
```
## Conditions
### Exists
`Exists` teste lexistence dau moins une ligne dans la sous-requête.
Renvoie `TRUE` si la sous-requête retourne une ou plusieurs lignes.
```sql
SELECT nom
FROM clients c
WHERE EXISTS (
SELECT 1
FROM commandes o
WHERE o.client_id = c.id
);
```
Le contenu du SELECT dans EXISTS na pas dimportance (on met parfois SELECT 1 par convention).
`NOT EXISTS` inverse la condition.
### IN / NOT IN
`IN` teste si une valeur est contenue dans lensemble retourné par la sous-requête.
```sql
SELECT nom
FROM produits
WHERE categorie_id IN (
SELECT id FROM categories WHERE actif = true
);
```
`NOT IN` inverse la condition.
### SOME
`ANY` permet de comparer une valeur avec le résultat dune sous-requête. Il est ainsi possible de vérifier si une valeur est égale, différente, supérieure, inférieur pour **au moins** une des valeurs de la sous-requête.
```sql
SELECT nom
FROM produits
WHERE prix > SOME (
SELECT prix_promo FROM promotions
);
```
### ALL
`ALL` permet de comparer une valeur avec le résultat dune sous-requête. Il est ainsi possible de vérifier si une valeur est égale, différente, supérieure, inférieur pour toutes valeurs de la sous-requête.
```sql
SELECT nom
FROM produits
WHERE prix > ALL (
SELECT prix_promo FROM promotions
);
```