jointures
162
Jointure.md
Normal file
162
Jointure.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# Jointures
|
||||
|
||||
Les jointures (joins en anglais) permettent de combiner des enregistrements de plusieurs tables d'une base de données en fonction d'une condition définie. Elles sont utilisées lorsque l'on veut extraire des données provenant de plusieurs sources qui partagent un lien commun, souvent une clé étrangère (foreign key).
|
||||
|
||||
Le type de jointure utilisé dépend du résultat attendu et de la structure des données.
|
||||
|
||||
## Jointure interne
|
||||
|
||||
`INNER JOIN` est le type de jointure le plus courant. Il ne renvoie que les lignes qui ont des correspondances exactes dans les deux tables gauche et droite.
|
||||
|
||||
```sql
|
||||
SELECT gauche.colonne, droite.colonne
|
||||
FROM gauche
|
||||
INNER JOIN droite ON gauche.id = droite.id;
|
||||
```
|
||||
|
||||
Dans cet exemple, seules les lignes qui ont le même id dans gauche et droite seront incluses dans le résultat.
|
||||
|
||||

|
||||
|
||||
## Jointure externe gauche
|
||||
|
||||
La jointure `LEFT JOIN` ou `LEFT OUTER JOIN` renvoie **toutes** les lignes de la table de gauche, même si elles n'ont pas de correspondance dans la table de droite. Si aucune correspondance n'est trouvée, les colonnes de la table de droite contiendront des valeurs NULL.
|
||||
|
||||
```sql
|
||||
SELECT gauche.colonne, droite.colonne
|
||||
FROM gauche
|
||||
LEFT JOIN droite
|
||||
ON gauche.id = droite.id;
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Jointure externe droite
|
||||
|
||||
`RIGHT JOIN` ou `RIGHT OUTER JOIN` est l'inverse de la jointure externe gauche. Elle renvoie **toutes** les lignes de la table de droite et les lignes correspondantes de la table de gauche. Si une ligne de la table de droite n'a pas de correspondance dans la table de gauche, les colonnes de la table de gauche auront des valeurs NULL.
|
||||
|
||||
```sql
|
||||
SELECT gauche.colonne, droite.colonne
|
||||
FROM gauche
|
||||
RIGHT JOIN droite
|
||||
ON gauche.id = droite.id;
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||
```sql
|
||||
SELECT gauche.colonne, droite.colonne
|
||||
FROM gauche
|
||||
FULL JOIN droite
|
||||
ON gauche.id = droite.id;
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 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).
|
||||
|
||||
```sql
|
||||
SELECT gauche.colonne, droite.colonne
|
||||
FROM gauche
|
||||
LEFT JOIN droite
|
||||
ON gauche.id = droite.id
|
||||
WHERE droite.id IS NULL;
|
||||
```
|
||||

|
||||
|
||||
Cela permet de trouver les lignes de gauche sans correspondance dans la table de droite.
|
||||
|
||||
Un jointure d'exclusion à droite (right 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 gauche sont NULL).
|
||||
|
||||
```sql
|
||||
SELECT gauche.colonne, droite.colonne
|
||||
FROM gauche
|
||||
RIGHT JOIN droite
|
||||
ON gauche.id = droite.id
|
||||
WHERE gauche IS NULL;
|
||||
```
|
||||

|
||||
|
||||
## Jointure croisée ou produit cartésien
|
||||
|
||||
La jointure croisée renvoie le produit cartésien des deux tables. Chaque ligne de la première table est combinée avec chaque ligne de la deuxième table. Cela produit un très grand nombre de lignes de résultat.
|
||||
|
||||
```sql
|
||||
SELECT gauche.colonne, droite.colonne
|
||||
FROM gauche
|
||||
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.
|
||||
|
||||
## 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`.
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM A, B;
|
||||
```
|
||||
|
||||
Le résultat de cette requête est strictement équivalent au produit cartésien `CROSS JOIN`. Si une condition `WHERE` est ajoutée, l'équivalent est une jointure `INNER`.
|
||||
|
||||
```sql
|
||||
SELECT *
|
||||
FROM A, B
|
||||
WHERE A.id = B.a_id;
|
||||
```
|
||||
|
||||
## EXISTS
|
||||
|
||||
Les jointures d'exclusion peuvent aussi s'écrire avec une sous requête et une condition `EXISTS`.
|
||||
|
||||
```sql
|
||||
SELECT gauxhe.*
|
||||
FROM gauche g
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM droite d
|
||||
WHERE d.g_id = g.id
|
||||
);
|
||||
```
|
||||
|
||||
`SELECT 1` car nous ne voulons pas récupérer de valeur de la table mais uniquement savoir si la ligne existe ou pas.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
SELECT g.*
|
||||
FROM gauche g
|
||||
WHERE g.id NOT IN (
|
||||
SELECT d.g_id
|
||||
FROM droite d
|
||||
);
|
||||
```
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
```sql
|
||||
SELECT G.colonne, D.colonne
|
||||
FROM table G, table D
|
||||
WHERE G.nom = D.nom;
|
||||
```
|
||||

|
||||
|
||||
|
||||
## lateral
|
||||
@@ -1,7 +1,7 @@
|
||||
-- Réponses
|
||||
|
||||
-- 1a : Quel est le nombre total de ticket ?
|
||||
-- 101 615
|
||||
-- 101 616
|
||||
select count(*) as nb_ticket from ticket;
|
||||
|
||||
-- 1b : Quel est le nombre total d'adhérents ?
|
||||
@@ -9,34 +9,34 @@ select count(*) as nb_ticket from ticket;
|
||||
select count(*) as nb_adherent from adherent;
|
||||
|
||||
-- 2 : Calculer le chiffre d’affaires global.
|
||||
-- 1 881 766.53085
|
||||
-- 1 914 792.39585
|
||||
select sum(quantite * prix_unitaire) as chiffre_affaire from ligne;
|
||||
|
||||
-- 3a : Pour chaque adhérent, afficher son nom et son nombre de ticket.
|
||||
-- 3a : Pour chaque adhérent unique, afficher son nom et son nombre de ticket.
|
||||
select a.nom,
|
||||
count(t.id) as nb_ticket
|
||||
from adherent a
|
||||
join ticket t on a.id = t.client_id
|
||||
join ticket t on a.id = t.adherent_id
|
||||
group by a.id;
|
||||
|
||||
-- 3b : Pour chaque adhérent, afficher son nom et son nombre de ticket.
|
||||
select a.nom,
|
||||
-- 3b : Quel est le détail du nombre de ticket pour ceux dont le nom de famille est Lavergne ?
|
||||
select a.nom, a.prenom,
|
||||
count(t.id) as nb_ticket
|
||||
from adherent a
|
||||
join ticket t on a.id = t.client_id
|
||||
join ticket t on a.id = t.adherent_id
|
||||
where a.nom = 'Lavergne'
|
||||
group by a.id;
|
||||
|
||||
-- 3c : Pour chaque adhérent, afficher son nom et son nombre de ticket.
|
||||
select a.nom,
|
||||
-- 3c : Quels sont les personnes qu iont exactement 72 tickets ?
|
||||
select a.nom, a.prenom,
|
||||
count(t.id) as nb_ticket
|
||||
from adherent a
|
||||
join ticket t on a.id = t.client_id
|
||||
join ticket t on a.id = t.adherent_id
|
||||
group by a.id
|
||||
having count(t.id) = 72;
|
||||
|
||||
-- 4 : Calculer le montant moyen d’un ticket.
|
||||
-- 18.52
|
||||
-- 4a : Calculer le montant moyen d’un ticket.
|
||||
-- 18.84
|
||||
select avg(total_ticket) as panier_moyen
|
||||
from (
|
||||
select t.id, sum(l.quantite * l.prix_unitaire) as total_ticket
|
||||
@@ -45,21 +45,59 @@ from (
|
||||
group by t.id
|
||||
) sous_requete;
|
||||
|
||||
-- 4b : Calculer le nombre moyen d'article distinct d'un ticket.
|
||||
-- 6.69
|
||||
SELECT avg(nb_articles_distincts) AS moyenne_articles_distincts
|
||||
FROM (
|
||||
SELECT t.id, COUNT(DISTINCT l.article_code) AS nb_articles_distincts
|
||||
FROM ticket t
|
||||
JOIN ligne l ON l.ticket_id = t.id
|
||||
GROUP BY t.id
|
||||
) sub;
|
||||
|
||||
-- 4c Calculer le nombre moyen d'article d'un ticket. Les articles facturés au poids comptent pour 1.
|
||||
-- 7.21
|
||||
SELECT AVG(nb_articles) AS moyenne_articles_par_ticket
|
||||
FROM (
|
||||
SELECT t.id,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN a.factpoids THEN 1 -- articles à la pièce
|
||||
ELSE l.quantite -- articles au poids : 1 unité
|
||||
END
|
||||
) AS nb_articles
|
||||
FROM ticket t
|
||||
JOIN ligne l ON l.ticket_id = t.id
|
||||
JOIN article a ON a.code = l.article_code
|
||||
GROUP BY t.id
|
||||
) sub;
|
||||
|
||||
|
||||
-- 5 : Afficher le produit le plus cher et le produit le moins cher (avec leur prix).
|
||||
-- Pistache 63
|
||||
select article.article, prix
|
||||
from article
|
||||
order by prix desc
|
||||
limit 1;
|
||||
|
||||
-- Courgette Mini Fleur
|
||||
select article.article, prix
|
||||
from article
|
||||
order by prix asc
|
||||
limit 1;
|
||||
limit 10;
|
||||
|
||||
-- 6a : Pour chaque famille, afficher le nom de la famille et le nombre d'articles associés.
|
||||
select f.famille, count(a.code) as nb_produits
|
||||
from famille f
|
||||
left join article a on f.code = a.famille
|
||||
left join article a on f.code = a.famille_code
|
||||
group by f.famille;
|
||||
|
||||
-- 6b
|
||||
-- 29
|
||||
select f.famille, count(a.code) as nb_produits
|
||||
from famille f
|
||||
left join article a on f.code = a.famille_code
|
||||
where f.code = '02CHOU'
|
||||
group by f.famille;
|
||||
|
||||
-- 7 : Afficher, pour chaque mois, le chiffre d’affaires réalisé.
|
||||
@@ -71,18 +109,19 @@ group by date_trunc('month', t.date_ticket)
|
||||
order by mois;
|
||||
|
||||
-- 8 : Trouver les 3 adhérents qui ont dépensé le plus en montant total.
|
||||
select c.nom, sum(l.quantite * l.prix_unitaire) as total_depense
|
||||
from adherent c
|
||||
join ticket t on c.id = t.client_id
|
||||
select a.nom, sum(l.quantite * l.prix_unitaire) as total_depense
|
||||
from adherent a
|
||||
join ticket t on a.id = t.adherent_id
|
||||
join ligne l on t.id = l.ticket_id
|
||||
group by c.nom
|
||||
group by a.nom
|
||||
order by total_depense desc
|
||||
limit 3;
|
||||
|
||||
-- 9 : Afficher l'article ayant généré le plus de ventes en quantité totale vendue.
|
||||
select a.article, sum(l.quantite) as total_vendu
|
||||
from article a
|
||||
join ligne l on a.code = l.article
|
||||
join ligne l on a.code = l.article_code
|
||||
where a.factpoids = false
|
||||
group by a.article
|
||||
order by total_vendu desc
|
||||
limit 1
|
||||
@@ -91,166 +130,7 @@ limit 1
|
||||
select f.famille,
|
||||
sum(l.quantite * l.prix_unitaire) as total_famille
|
||||
from famille f
|
||||
join article a on f.famille = a.famille
|
||||
join ligne l on a.code = l.article
|
||||
join article a on f.code = a.famille_code
|
||||
join ligne l on a.code = l.article_code
|
||||
group by f.famille
|
||||
order by total_famille desc;
|
||||
|
||||
-- ----------
|
||||
|
||||
-- 1 : Intersection (INNER JOIN)
|
||||
SELECT t.id_ticket, t.date_vente, c.nom AS client
|
||||
FROM ticket t
|
||||
INNER JOIN client c ON c.id_client = t.id_client;
|
||||
|
||||
-- 2 : LEFT JOIN (client sans ticket)
|
||||
SELECT c.id_client, c.nom, COUNT(t.id_ticket) AS nb_ticket
|
||||
FROM client c
|
||||
LEFT JOIN ticket t ON t.id_client = c.id_client
|
||||
GROUP BY c.id_client, c.nom
|
||||
ORDER BY c.nom;
|
||||
|
||||
-- 3 : RIGHT JOIN (ticket sans client)
|
||||
SELECT t.id_ticket, t.date_vente, c.nom AS client
|
||||
FROM client c
|
||||
RIGHT JOIN ticket t ON c.id_client = t.id_client;
|
||||
|
||||
-- 4 : FULL OUTER JOIN (union)
|
||||
SELECT
|
||||
c.id_client, c.nom,
|
||||
t.id_ticket, t.date_vente,
|
||||
CASE
|
||||
WHEN t.id_ticket IS NULL THEN 'client_sans_ticket'
|
||||
WHEN c.id_client IS NULL THEN 'ticket_sans_client'
|
||||
ELSE 'apparié'
|
||||
END AS statut
|
||||
FROM client c
|
||||
FULL OUTER JOIN ticket t ON c.id_client = t.id_client
|
||||
ORDER BY statut, c.nom NULLS LAST, t.id_ticket;
|
||||
|
||||
|
||||
-- 5 : SEMI-JOIN (existence)
|
||||
|
||||
--Lister uniquement les client qui ont acheté au moins un produit. en SQL standard, cela se fait avec EXISTS.
|
||||
|
||||
--Lister tous les produits et indiquer s’ils ont été vendus au moins une fois (utiliser un CASE ou COALESCE).
|
||||
|
||||
SELECT
|
||||
p.id_produit,
|
||||
p.nom_produit,
|
||||
CASE WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM ligne lt
|
||||
WHERE lt.id_produit = p.id_produit
|
||||
) THEN TRUE ELSE FALSE END AS deja_vendu
|
||||
FROM Produits p
|
||||
ORDER BY p.nom_produit;
|
||||
|
||||
SELECT
|
||||
p.id_produit,
|
||||
p.nom_produit,
|
||||
COALESCE(SUM(CASE WHEN lt.id_ligne IS NOT NULL THEN 1 ELSE 0 END), 0) > 0 AS deja_vendu
|
||||
FROM Produits p
|
||||
LEFT JOIN ligne lt ON lt.id_produit = p.id_produit
|
||||
GROUP BY p.id_produit, p.nom_produit;
|
||||
|
||||
-- 6 : ANTI-JOIN (différence)
|
||||
|
||||
Lister les client qui n’ont jamais acheté de produit.
|
||||
utiliser NOT EXISTS ou une jointure + WHERE.
|
||||
|
||||
-- 7 : Jointure avec condition multiple
|
||||
|
||||
Lister les produits avec leur famille, même si certains produits n’ont pas de famille renseignée.
|
||||
|
||||
-- 8 : Auto-join (self join)
|
||||
|
||||
SELECT DISTINCT
|
||||
c1.nom AS client_1,
|
||||
c2.nom AS client_2
|
||||
FROM client c1
|
||||
JOIN ticket t1 ON t1.id_client = c1.id_client
|
||||
JOIN ligne lt1 ON lt1.id_ticket = t1.id_ticket
|
||||
JOIN ligne lt2 ON lt2.id_produit = lt1.id_produit
|
||||
JOIN ticket t2 ON t2.id_ticket = lt2.id_ticket
|
||||
JOIN client c2 ON c2.id_client = t2.id_client
|
||||
WHERE c1.id_client < c2.id_client;
|
||||
|
||||
|
||||
-- 9 : Produit cartésien
|
||||
|
||||
Lister toutes les combinaisons possibles de familles et de client (sans condition de jointure).
|
||||
Attention : nombre de lignes = nb_familles × nb_client.
|
||||
|
||||
-- 10 : Jointure filtrée
|
||||
|
||||
Lister les ticket contenant au moins un produit de la famille "Boissons".
|
||||
|
||||
SELECT DISTINCT c.id_client, c.nom
|
||||
FROM client c
|
||||
JOIN ticket t ON t.id_client = c.id_client
|
||||
JOIN ligne lt ON lt.id_ticket = t.id_ticket
|
||||
JOIN Produits p ON p.id_produit = lt.id_produit
|
||||
JOIN Familles f ON f.id_famille = p.id_famille
|
||||
WHERE f.nom_famille = 'Boissons'
|
||||
ORDER BY c.nom;
|
||||
|
||||
-- 11
|
||||
SELECT c.id_client, c.nom
|
||||
FROM client c
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM ticket t
|
||||
JOIN ligne lt ON lt.id_ticket = t.id_ticket
|
||||
JOIN Produits p ON p.id_produit = lt.id_produit
|
||||
JOIN Familles f ON f.id_famille = p.id_famille
|
||||
WHERE t.id_client = c.id_client
|
||||
AND f.nom_famille = 'Boissons'
|
||||
)
|
||||
ORDER BY c.nom;
|
||||
|
||||
SELECT c.id_client, c.nom
|
||||
FROM client c
|
||||
LEFT JOIN (
|
||||
SELECT DISTINCT t.id_client
|
||||
FROM ticket t
|
||||
JOIN ligne lt ON lt.id_ticket = t.id_ticket
|
||||
JOIN Produits p ON p.id_produit = lt.id_produit
|
||||
JOIN Familles f ON f.id_famille = p.id_famille
|
||||
WHERE f.nom_famille = 'Boissons'
|
||||
) acheteurs_boissons
|
||||
ON acheteurs_boissons.id_client = c.id_client
|
||||
WHERE acheteurs_boissons.id_client IS NULL
|
||||
ORDER BY c.nom;
|
||||
|
||||
|
||||
-- total des ventes par famille
|
||||
|
||||
SELECT
|
||||
f.nom_famille,
|
||||
SUM(lt.quantite * lt.prix_unitaire) AS total_ventes
|
||||
FROM Familles f
|
||||
JOIN Produits p ON p.id_famille = f.id_famille
|
||||
JOIN ligne lt ON lt.id_produit = p.id_produit
|
||||
GROUP BY f.nom_famille
|
||||
ORDER BY total_ventes DESC;
|
||||
|
||||
--
|
||||
select f.code, f.famille, count(a.code) as nb_produits
|
||||
from famille f
|
||||
left join article a on f.code = a.famille
|
||||
group by f.code having count(a.code) = 0 order by f.code;
|
||||
|
||||
select distinct a.famille from article a
|
||||
left join famille f on f.code = a.famille
|
||||
where f.code is null
|
||||
order by a.famille
|
||||
|
||||
SELECT DISTINCT ON (f.code)
|
||||
f.code AS famille_id,
|
||||
f.famille AS famille_nom,
|
||||
a.article AS article_exemple
|
||||
FROM famille f
|
||||
LEFT JOIN article a ON a.famille = f.code
|
||||
where f.famille is null
|
||||
ORDER BY f.code, a.code;
|
||||
|
||||
261
Réponses/jointure.sql
Normal file
261
Réponses/jointure.sql
Normal file
@@ -0,0 +1,261 @@
|
||||
|
||||
-- ----------
|
||||
|
||||
-- Combien d'adhérents n’ont jamais acheté d'article ?
|
||||
SELECT COUNT(*) AS nb_adherents_sans_achat
|
||||
FROM adherent a
|
||||
LEFT JOIN ticket t ON t.adherent_id = a.id
|
||||
LEFT JOIN ligne l ON l.ticket_id = t.id
|
||||
WHERE l.id IS NULL;
|
||||
|
||||
SELECT COUNT(*) AS nb_adherents_sans_achat
|
||||
FROM adherent a
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM ticket t
|
||||
JOIN ligne l ON l.ticket_id = t.id
|
||||
WHERE t.adherent_id = a.id
|
||||
);
|
||||
|
||||
|
||||
-- Combien d'adhérents n’ont aucun ticket ?
|
||||
|
||||
SELECT COUNT(*) AS nb_adherents_sans_ticket
|
||||
FROM adherent a
|
||||
LEFT JOIN ticket t ON t.adherent_id = a.id
|
||||
WHERE t.id IS NULL;
|
||||
|
||||
SELECT COUNT(*) AS nb_adherents_sans_ticket
|
||||
FROM adherent a
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM ticket t
|
||||
WHERE t.adherent_id = a.id
|
||||
);
|
||||
|
||||
-- Version spécifique PostgreSQL Ne fontionne pas
|
||||
|
||||
SELECT
|
||||
COUNT(*) FILTER (
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM ticket t WHERE t.adherent_id = a.id
|
||||
)
|
||||
) AS nb_sans_ticket,
|
||||
|
||||
COUNT(*) FILTER (
|
||||
WHERE EXISTS (
|
||||
SELECT 1 FROM ticket t WHERE t.adherent_id = a.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM ticket t
|
||||
JOIN ligne l ON l.ticket_id = t.id
|
||||
WHERE t.adherent_id = a.id
|
||||
)
|
||||
) AS nb_tickets_vides,
|
||||
|
||||
COUNT(*) FILTER (
|
||||
WHERE EXISTS (
|
||||
SELECT 1
|
||||
FROM ticket t
|
||||
JOIN ligne l ON l.ticket_id = t.id
|
||||
WHERE t.adherent_id = a.id
|
||||
)
|
||||
) AS nb_acheteurs
|
||||
FROM adherent a;
|
||||
|
||||
--
|
||||
|
||||
SELECT
|
||||
COUNT(CASE
|
||||
WHEN NOT EXISTS (SELECT 1 FROM ticket t WHERE t.adherent_id = a.id)
|
||||
THEN 1 END) AS nb_sans_ticket,
|
||||
|
||||
COUNT(CASE
|
||||
WHEN EXISTS (SELECT 1 FROM ticket t WHERE t.adherent_id = a.id)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM ticket t
|
||||
JOIN ligne l ON l.ticket_id = t.id
|
||||
WHERE t.adherent_id = a.id
|
||||
)
|
||||
THEN 1 END) AS nb_tickets_vides,
|
||||
|
||||
COUNT(CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM ticket t
|
||||
JOIN ligne l ON l.ticket_id = t.id
|
||||
WHERE t.adherent_id = a.id
|
||||
)
|
||||
THEN 1 END) AS nb_acheteurs
|
||||
FROM adherent a;
|
||||
|
||||
-- 13 :
|
||||
SELECT COUNT(*) AS nb_adherents_un_seul_article
|
||||
FROM (
|
||||
SELECT a.id
|
||||
FROM adherent a
|
||||
JOIN ticket t ON t.adherent_id = a.id
|
||||
JOIN ligne l ON l.ticket_id = t.id
|
||||
GROUP BY a.id
|
||||
HAVING COUNT(DISTINCT l.article_code) = 1
|
||||
) sub;
|
||||
|
||||
|
||||
-- 1 : Intersection (INNER JOIN)
|
||||
SELECT t.id_ticket, t.date_vente, c.nom AS client
|
||||
FROM ticket t
|
||||
INNER JOIN client c ON c.id_client = t.id_client;
|
||||
|
||||
-- 2 : LEFT JOIN (client sans ticket)
|
||||
SELECT c.id_client, c.nom, COUNT(t.id_ticket) AS nb_ticket
|
||||
FROM client c
|
||||
LEFT JOIN ticket t ON t.id_client = c.id_client
|
||||
GROUP BY c.id_client, c.nom
|
||||
ORDER BY c.nom;
|
||||
|
||||
-- 3 : RIGHT JOIN (ticket sans client)
|
||||
SELECT t.id_ticket, t.date_vente, c.nom AS client
|
||||
FROM client c
|
||||
RIGHT JOIN ticket t ON c.id_client = t.id_client;
|
||||
|
||||
-- 4 : FULL OUTER JOIN (union)
|
||||
SELECT
|
||||
c.id_client, c.nom,
|
||||
t.id_ticket, t.date_vente,
|
||||
CASE
|
||||
WHEN t.id_ticket IS NULL THEN 'client_sans_ticket'
|
||||
WHEN c.id_client IS NULL THEN 'ticket_sans_client'
|
||||
ELSE 'apparié'
|
||||
END AS statut
|
||||
FROM client c
|
||||
FULL OUTER JOIN ticket t ON c.id_client = t.id_client
|
||||
ORDER BY statut, c.nom NULLS LAST, t.id_ticket;
|
||||
|
||||
|
||||
-- 5 : SEMI-JOIN (existence)
|
||||
|
||||
--Lister uniquement les client qui ont acheté au moins un produit. en SQL standard, cela se fait avec EXISTS.
|
||||
|
||||
--Lister tous les produits et indiquer s’ils ont été vendus au moins une fois (utiliser un CASE ou COALESCE).
|
||||
|
||||
SELECT
|
||||
p.id_produit,
|
||||
p.nom_produit,
|
||||
CASE WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM ligne lt
|
||||
WHERE lt.id_produit = p.id_produit
|
||||
) THEN TRUE ELSE FALSE END AS deja_vendu
|
||||
FROM Produits p
|
||||
ORDER BY p.nom_produit;
|
||||
|
||||
SELECT
|
||||
p.id_produit,
|
||||
p.nom_produit,
|
||||
COALESCE(SUM(CASE WHEN lt.id_ligne IS NOT NULL THEN 1 ELSE 0 END), 0) > 0 AS deja_vendu
|
||||
FROM Produits p
|
||||
LEFT JOIN ligne lt ON lt.id_produit = p.id_produit
|
||||
GROUP BY p.id_produit, p.nom_produit;
|
||||
|
||||
-- 6 : ANTI-JOIN (différence)
|
||||
|
||||
Lister les client qui n’ont jamais acheté de produit.
|
||||
utiliser NOT EXISTS ou une jointure + WHERE.
|
||||
|
||||
-- 7 : Jointure avec condition multiple
|
||||
|
||||
Lister les produits avec leur famille, même si certains produits n’ont pas de famille renseignée.
|
||||
|
||||
-- 8 : Auto-join (self join)
|
||||
|
||||
SELECT DISTINCT
|
||||
c1.nom AS client_1,
|
||||
c2.nom AS client_2
|
||||
FROM client c1
|
||||
JOIN ticket t1 ON t1.id_client = c1.id_client
|
||||
JOIN ligne lt1 ON lt1.id_ticket = t1.id_ticket
|
||||
JOIN ligne lt2 ON lt2.id_produit = lt1.id_produit
|
||||
JOIN ticket t2 ON t2.id_ticket = lt2.id_ticket
|
||||
JOIN client c2 ON c2.id_client = t2.id_client
|
||||
WHERE c1.id_client < c2.id_client;
|
||||
|
||||
|
||||
-- 9 : Produit cartésien
|
||||
|
||||
Lister toutes les combinaisons possibles de familles et de client (sans condition de jointure).
|
||||
Attention : nombre de lignes = nb_familles × nb_client.
|
||||
|
||||
-- 10 : Jointure filtrée
|
||||
|
||||
Lister les ticket contenant au moins un produit de la famille "Boissons".
|
||||
|
||||
SELECT DISTINCT c.id_client, c.nom
|
||||
FROM client c
|
||||
JOIN ticket t ON t.id_client = c.id_client
|
||||
JOIN ligne lt ON lt.id_ticket = t.id_ticket
|
||||
JOIN Produits p ON p.id_produit = lt.id_produit
|
||||
JOIN Familles f ON f.id_famille = p.id_famille
|
||||
WHERE f.nom_famille = 'Boissons'
|
||||
ORDER BY c.nom;
|
||||
|
||||
-- 11
|
||||
SELECT c.id_client, c.nom
|
||||
FROM client c
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM ticket t
|
||||
JOIN ligne lt ON lt.id_ticket = t.id_ticket
|
||||
JOIN Produits p ON p.id_produit = lt.id_produit
|
||||
JOIN Familles f ON f.id_famille = p.id_famille
|
||||
WHERE t.id_client = c.id_client
|
||||
AND f.nom_famille = 'Boissons'
|
||||
)
|
||||
ORDER BY c.nom;
|
||||
|
||||
SELECT c.id_client, c.nom
|
||||
FROM client c
|
||||
LEFT JOIN (
|
||||
SELECT DISTINCT t.id_client
|
||||
FROM ticket t
|
||||
JOIN ligne lt ON lt.id_ticket = t.id_ticket
|
||||
JOIN Produits p ON p.id_produit = lt.id_produit
|
||||
JOIN Familles f ON f.id_famille = p.id_famille
|
||||
WHERE f.nom_famille = 'Boissons'
|
||||
) acheteurs_boissons
|
||||
ON acheteurs_boissons.id_client = c.id_client
|
||||
WHERE acheteurs_boissons.id_client IS NULL
|
||||
ORDER BY c.nom;
|
||||
|
||||
|
||||
-- total des ventes par famille
|
||||
|
||||
SELECT
|
||||
f.nom_famille,
|
||||
SUM(lt.quantite * lt.prix_unitaire) AS total_ventes
|
||||
FROM Familles f
|
||||
JOIN Produits p ON p.id_famille = f.id_famille
|
||||
JOIN ligne lt ON lt.id_produit = p.id_produit
|
||||
GROUP BY f.nom_famille
|
||||
ORDER BY total_ventes DESC;
|
||||
|
||||
--
|
||||
select f.code, f.famille, count(a.code) as nb_produits
|
||||
from famille f
|
||||
left join article a on f.code = a.famille
|
||||
group by f.code having count(a.code) = 0 order by f.code;
|
||||
|
||||
select distinct a.famille from article a
|
||||
left join famille f on f.code = a.famille
|
||||
where f.code is null
|
||||
order by a.famille
|
||||
|
||||
SELECT DISTINCT ON (f.code)
|
||||
f.code AS famille_id,
|
||||
f.famille AS famille_nom,
|
||||
a.article AS article_exemple
|
||||
FROM famille f
|
||||
LEFT JOIN article a ON a.famille = f.code
|
||||
where f.famille is null
|
||||
ORDER BY f.code, a.code;
|
||||
29
exercice.md
29
exercice.md
@@ -1,34 +1,41 @@
|
||||
# Exercices
|
||||
|
||||
## Série 1
|
||||
## 1. Fonctions d'agrégation
|
||||
|
||||
- 1a : Quel est le nombre total de ticket ?
|
||||
- 1b : Quel est le nombre total d'adhérents ?
|
||||
- 2 : Calculer le chiffre d’affaires global.
|
||||
- 3a : Pour chaque adhérent, afficher son nom et son nombre de ticket.
|
||||
- 3a : Pour chaque adhérent unique, afficher son nom et son nombre de ticket.
|
||||
- 3b : Quel est le détail du nombre de ticket pour ceux dont le nom de famille est Lavergne ?
|
||||
- 3c : Quels sont les personnes qu iont exactement 72 tickets ?
|
||||
- 4 : Calculer le montant moyen d’un ticket.
|
||||
- 4a : Calculer le montant moyen d’un ticket.
|
||||
- 4b : Calculer le nombre moyen d'article distinct d'un ticket.
|
||||
- 4c : Calculer le nombre moyen d'article d'un ticket. Les articles facturés au poids comptent pour 1.
|
||||
- 5 : Afficher l'article le plus cher et l'article le moins cher (avec leur prix).
|
||||
- 6a : Pour chaque famille, afficher le nom de la famille et le nombre d'articles associés.
|
||||
- 6b : Quel est le nombre d'article de la famille
|
||||
- 6b : Quel est le nombre d'article de la famille 02CHOU
|
||||
- 7 : Afficher, pour chaque mois, le chiffre d’affaires réalisé.
|
||||
- 8 : Trouver l'adhérent qui a dépensé le plus en montant total.
|
||||
- 9 : Afficher l'article ayant généré le plus de ventes en quantité totale vendue.
|
||||
- 8 : Trouver les 3 adhérents qui ont dépensé le plus en montant total.
|
||||
- 9a : Afficher l'article facturé au poids ayant généré le plus de ventes en quantité totale vendue.
|
||||
- 9b : Afficher l'article facturé à l'unité ayant généré le plus de ventes en quantité totale vendue.
|
||||
- 10 : Pour chaque famille, afficher le montant total des ventes.
|
||||
|
||||
## Série 2
|
||||
## 2. Jointures
|
||||
|
||||
- 1a : Combien d'adhérents n’ont jamais acheté d'article ?
|
||||
- 1b : Combien d'adhérents n’ont aucun ticket ?
|
||||
- 1c : Combien de tickets sont vides (sans ligne)
|
||||
- 2a : Quel est l'article qui n'a jamais été commandé ?
|
||||
- 2b : Quels sont les articles qui apparaissent qu'une seule fois
|
||||
- 3 : Lister les articles dont la famille est absente
|
||||
|
||||
- 1 : Lister tous les tickets avec le nom du client. Afficher uniquement les tickets qui ont un client existant.
|
||||
- 2 : Lister tous les clients et le nombre de tickets associés, même les clients qui n’ont pas encore de ticket doivent apparaître (avec 0).
|
||||
- 3 : Lister tous les tickets, avec le nom du client s’il existe. Si un ticket a perdu sa référence client (valeur orpheline), il doit tout de même apparaître.
|
||||
- 4 : Lister tous les clients et tous les tickets, même si la correspondance n’existe pas. Union des clients sans tickets et des tickets sans clients.
|
||||
- 5 : Lister uniquement les clients qui ont acheté au moins un produit.
|
||||
- 6 : Lister les clients qui n’ont jamais acheté de produit.
|
||||
|
||||
- 7 : Lister les produits avec leur famille, même si certains produits n’ont pas de famille renseignée.
|
||||
- 8 : Lister tous les couples de clients qui habitent dans la même ville.
|
||||
- 9 : Lister toutes les combinaisons possibles de familles et de clients (sans condition de jointure).
|
||||
- 10 : Lister les tickets contenant au moins un produit de la famille "Boissons".
|
||||
|
||||
|
||||
- Lister
|
||||
|
||||
12
jointures/fullouterjoin.svg
Normal file
12
jointures/fullouterjoin.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="800" height="600" version="1.1">
|
||||
<g style="stroke:#000000;stroke-width:4">
|
||||
<path style="fill:#f00;" 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 |
12
jointures/innerjoin.svg
Normal file
12
jointures/innerjoin.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="800" height="600" version="1.1">
|
||||
<g style="stroke:#000000;stroke-width:4">
|
||||
<path style="fill:#f00;" 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:#fff;" 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:#fff;" 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 |
12
jointures/leftantijoin.svg
Normal file
12
jointures/leftantijoin.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="800" height="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:#fff;" 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 |
12
jointures/leftjoin.svg
Normal file
12
jointures/leftjoin.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="800" height="600" version="1.1">
|
||||
<g style="stroke:#000000;stroke-width:4">
|
||||
<path style="fill:#f00;" 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:#fff;" 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 |
12
jointures/rightantijoin.svg
Normal file
12
jointures/rightantijoin.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="800" height="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:#fff;" 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 |
12
jointures/rightjoin.svg
Normal file
12
jointures/rightjoin.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="800" height="600" version="1.1">
|
||||
<g style="stroke:#000000;stroke-width:4">
|
||||
<path style="fill:#f00;" 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:#fff;" 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 |
83
jointures/td.md
Normal file
83
jointures/td.md
Normal file
@@ -0,0 +1,83 @@
|
||||
Le nombre de produit par catégories
|
||||
|
||||
```sql
|
||||
SELECT c.CategoryName, COUNT(p.ProductID) AS ProductCount
|
||||
FROM categories c
|
||||
JOIN products p ON c.category_id = p.category_id
|
||||
GROUP BY c.CategoryName;
|
||||
```
|
||||
|
||||
Les produits jamais commandés
|
||||
|
||||
```sql
|
||||
select * from products p
|
||||
left join order_details od on od.ProductID = p.ProductID
|
||||
where od.OrderDetailID is null;
|
||||
```
|
||||
|
||||
Les ventes mois par mois de Dodsworth
|
||||
|
||||
```sql
|
||||
select year(OrderDate), month(OrderDate), d.unit_price * d.quantity
|
||||
from order_details d
|
||||
join orders o on o.OrderID = d.OrderID
|
||||
join employees y on y.employee_id = o.employee_id
|
||||
where LastName = 'Dodsworth'
|
||||
group by year(OrderDate), month(OrderDate)
|
||||
```
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS calendrier (
|
||||
DateValue DATE PRIMARY KEY,
|
||||
YearValue INT,
|
||||
MonthValue INT,
|
||||
DayValue INT,
|
||||
WeekDayName VARCHAR(10),
|
||||
WeekDayNumber INT,
|
||||
WeekNumber INT,
|
||||
QuarterValue INT
|
||||
);
|
||||
```
|
||||
|
||||
```sql
|
||||
SET SESSION max_recursive_iterations = 100000;
|
||||
|
||||
INSERT INTO calendrier
|
||||
WITH RECURSIVE CalendarCTE AS (
|
||||
SELECT
|
||||
'2020-01-01' AS DateValue,
|
||||
YEAR('2020-01-01') AS YearValue,
|
||||
MONTH('2020-01-01') AS MonthValue,
|
||||
DAY('2020-01-01') AS DayValue,
|
||||
DAYNAME('2020-01-01') AS WeekDayName,
|
||||
WEEKDAY('2020-01-01') + 1 AS WeekDayNumber, -- WEEKDAY retourne de 0 à 6, on ajuste pour avoir 1 à 7
|
||||
WEEK('2020-01-01', 3) AS WeekNumber, -- Mode 3 : semaines commencent le lundi
|
||||
QUARTER('2020-01-01') AS QuarterValue
|
||||
UNION ALL
|
||||
SELECT
|
||||
DATE_ADD(DateValue, INTERVAL 1 DAY),
|
||||
YEAR(DATE_ADD(DateValue, INTERVAL 1 DAY)),
|
||||
MONTH(DATE_ADD(DateValue, INTERVAL 1 DAY)),
|
||||
DAY(DATE_ADD(DateValue, INTERVAL 1 DAY)),
|
||||
DAYNAME(DATE_ADD(DateValue, INTERVAL 1 DAY)),
|
||||
WEEKDAY(DATE_ADD(DateValue, INTERVAL 1 DAY)) + 1,
|
||||
WEEK(DATE_ADD(DateValue, INTERVAL 1 DAY), 3),
|
||||
QUARTER(DATE_ADD(DateValue, INTERVAL 1 DAY))
|
||||
FROM CalendarCTE
|
||||
WHERE DATE_ADD(DateValue, INTERVAL 1 DAY) <= '2030-12-31'
|
||||
)
|
||||
SELECT * FROM CalendarCTE;
|
||||
```
|
||||
|
||||
```sql
|
||||
select c.YearValue , c.MonthValue, sum(montant)
|
||||
from calendrier c
|
||||
left join
|
||||
(select
|
||||
o.OrderDate, d.unit_price * d.quantity as montant
|
||||
from order_details d
|
||||
left join orders o on o.OrderID = d.OrderID
|
||||
left join employees y on y.employee_id = o.employee_id
|
||||
where LastName = 'Dodsworth') k on k.OrderDate = c.DateValue
|
||||
group by c.YearValue , c.MonthValue
|
||||
```
|
||||
Reference in New Issue
Block a user