sous requetes
1
Home.md
1
Home.md
@@ -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)
|
||||||
|
|||||||
80
Jointure.md
80
Jointure.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, qu’il 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;
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
Le fait d’avoir des NULL des deux côtés est le cœur de l’intérêt du FULL OUTER JOIN :
|
||||||
|
|
||||||
|
Cela permet d’obtenir tous les enregistrements présents dans l’une ou l’autre table, même quand il n’existe 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 d’inventaires (ex. produits d’un magasin vs produits d’un fournisseur).
|
||||||
|
- la synchronisation de données (trouver ce qui manque d’un côté ou de l’autre).
|
||||||
|
- de l'audit de cohérence (détecter des écarts entre deux tables censées contenir la même information).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## Jointure d'exclusion
|
## Jointure d'exclusion
|
||||||
|
|
||||||
Un jointure d'exclusion à gauche (left anti-join) garde uniquement les lignes pour lesquelles il n’y a **pas** de correspondance (c’est-à-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 n’y a **pas** de correspondance (c’est-à-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 s’effectue à la condition qu’il 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 d’ambiguïté).
|
- 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.
|
- 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.
|
||||||
|
|
||||||
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.
|
|
||||||
- **Lisibilité** : les syntaxes modernes apportent plus de clarté et facilitent la compréhension de l’intention 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 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.
|
||||||
|
- **Lisibilité** : les syntaxes modernes apportent plus de clarté et facilitent la compréhension de l’intention 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;
|
||||||
```
|
```
|
||||||

|
|
||||||
|
|
||||||
|
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 n’ont jamais acheté d'article ?
|
-- 1a Combien d'adhérents n’ont 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 n’ont 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 n’ont aucun ticket ?
|
-- Combien d'adhérents n’ont 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
|
||||||
|
|
||||||
|
|||||||
12
jointures/fullantijoin.svg
Normal file
12
jointures/fullantijoin.svg
Normal file
@@ -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
86
sousrequete.md
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
# Sous requête
|
||||||
|
|
||||||
|
Une sous-requête (subquery) est une requête SQL placée à l’intérieur d’une 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 l’existence d’au 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 n’a pas d’importance (on met parfois SELECT 1 par convention).
|
||||||
|
|
||||||
|
`NOT EXISTS` inverse la condition.
|
||||||
|
|
||||||
|
### IN / NOT IN
|
||||||
|
|
||||||
|
`IN` teste si une valeur est contenue dans l’ensemble 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 d’une 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 d’une 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
|
||||||
|
);
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user