[[04_Requêtes sur 2 tables]]
# Méthodologie : Déterminer et Construire les Requêtes
## Introduction
Écrire une requête SQL sans réflexion préalable est une erreur.
***Le SQL est la traduction technique d’un raisonnement logique.***
>[!tip] Avant d’écrire du code, il faut :
>
>1. Comprendre ce que représente un enregistrement attendu.
>2. Identifier les données nécessaires.
>3. Vérifier si ces données existent.
>4. Déterminer si certaines doivent être calculées.
>5. Organiser les requêtes dans le bon ordre.
---
## Objectifs
À la fin de ce chapitre, vous serez capable de :
- Analyser une demande.
- Identifier les tables nécessaires.
- Vérifier si les données existent.
- Déterminer si des données doivent être calculées.
- Découper un problème en plusieurs requêtes.
- Construire la requête finale proprement.
---
## 1. Étape 1 — Comprendre la demande
### 1.1 Ouvrir et comprendre le schéma relationnel
Toujours commencer par :
- Identifier les tables
- Identifier les clés primaires
- Identifier les clés étrangères
- Comprendre les relations
Si vous ne regardez pas le schéma, vous travaillez au hasard.
---
### 1.2 Déterminer ce que représente un enregistrement
Il est important de comprendre ce que vous voulez avoir au final
>[!tip] Question obligatoire :
>
> Une enregistrement du résultat correspond à quoi ?
>
>Exemples :
>- Un client ?
>- Une commande ?
>- Un client avec son nombre de commandes ?
>- Une ville avec son chiffre d’affaires ?
>[!warning] Puis-je passer à la suite ?
>Si ce point n’est pas clair, vous ne pouvez pas écrire la requête.
---
## 2. Étape 2 — Les données existent-elles ?
Maintenant que je sais ce que je veux, je dois savoir si je vais pouvoir résoudre le problème : les données sont-elles dans la base de données ou puis-je les calculer à l'aide de ces données ?
### 2.1 Données déjà présentes
Si les données existent telles quelles, une simple sélection suffit.
>[!tips] Exemples
>
>- nom_client → table `Clients`
>- date_commande → table `Commandes`
>- montant_total → table `Commandes`
---
### 2.2 Données à calculer
Si je ne trouve pas la donnée dans un champ d'une table, je vais chercher à savoir si je peux la calculer à l'aide de données bien présentes dans la base de données.
>[!tip] Exemples
>- Nombre de commandes → `COUNT`
>- Total des ventes → `SUM`
>- Moyenne → `AVG`
>[!tip] Fonctions d'agrégat
>Généralement, Une donnée calculée implique :
>- `GROUP BY`
>- éventuellement `HAVING`
---
## 3. Étape 3 — Combien de requêtes ?
### Cas simple
Une seule requête suffit si :
- Toutes les données sont accessibles directement
- Les calculs peuvent être faits dans la même requête
---
### Cas complexe
Plusieurs requêtes sont nécessaires si :
- Une table nécessaire est le résultat d’un calcul
- Une requête doit servir d’entrée à une autre
- La logique est plus claire en plusieurs étapes
Si une table est le résultat d’une requête, on applique la méthode à cette requête intermédiaire.
---
## 4. Étape 4 — Préparer la requête
Toujours réfléchir dans cet ordre :
1. `FROM` — Quelles tables ?
2. `WHERE` — Quels filtres ?
3. `GROUP BY` — Faut-il regrouper ?
4. `HAVING` — Faut-il filtrer les groupes ?
5. `ORDER BY` — Faut-il trier ?
6. `SELECT` — Que veut-on afficher ?
Attention : ordre de réflexion ≠ ordre d’écriture SQL.
Pour vous aider, nous vous proposons de vous aider du schéma ci-dessous :
![[Preparer_sa_requete.pdf]]
Une fois rempli et fait pour chaque requête, ce schéma vous permettra décrire rapidement vos requête.
>[!tip] Corrections des ateliers
> Vous verrez que nous utilisons ce schéma pour la correction des exercices.
## 5. Exemple d'une demande amenant à une requête complexe
En utilisant la description des deux tables suivantes, on nous demande la liste des clients dont le chiffre d’affaires total est supérieur à la moyenne du chiffre d’affaires de tous les clients.
#### La table *Clients*
| id_client | nom_client | ville_client | date_inscription |
| --------- | ---------- | ------------ | ---------------- |
| 1 | Martin | Paris | 2022-03-15 |
| 2 | Dupont | Lyon | 2021-11-02 |
| 3 | Bernard | Marseille | 2023-01-20 |
| 4 | Petit | Lille | 2022-07-08 |
| 5 | Robert | Bordeaux | 2023-05-12 |
#### La table *Commandes*
| id_commande | id_client | date_commande | montant_total |
| ----------- | --------- | ------------- | ------------- |
| 101 | 1 | 2023-01-10 | 250.00 |
| 102 | 1 | 2023-02-18 | 120.00 |
| 103 | 2 | 2023-03-05 | 560.00 |
| 104 | 2 | 2023-04-22 | 80.00 |
| 105 | 2 | 2023-06-01 | 310.00 |
| 106 | 3 | 2023-07-14 | 150.00 |
| 107 | 4 | 2023-08-03 | 400.00 |
### Ai-je les données pour répondre à cette demande ?
Dans les tables, je ne trouve ni le chiffre d'affaires total des clients, ni la moyenne du chiffre d’affaires de tous les clients. Puis-je les calculer ?
1- Le chiffre d'affaire total pour un client peut se calculer en faisant la somme des *montant_total*
2- La moyenne du chiffre d’affaires de tous les clients, peut se calculer après avoir fait le calcul du point 1-
je peux donc en conclure que je peux répondre à la demande.
### Combien de requête me faudra-t-il ?
1. Il me faut ***une première requête*** qui calcule **les chiffres d'affaires par client** et les compare à **la moyenne des chiffres d'affaires**. cette requête aura en entrée les tables *Clients* et *Commandes* et une deuxième requête.
2. En effet, La moyenne des chiffres d'affaires n'étant pas présente dans la base de données, je dois faire ***une deuxième requête*** qui retourne cette valeur.
3. En entrée de cette requête, il faut avoir le chiffre d'affaire de chaque client que l'on va obtenir à l'aide d'***une troisième requête***.
Ce qui donne le diagramme suivant :
```mermaid
graph TD
A@{ shape: text, label: "Clients" }-->C["3ème Requête"]
B@{ shape: text, label: "Commandes" }-->C
C-->D@{ shape: text, label: "Chiffre d'affaires par client" }
D-->E["2ème Requête"]
E-->F@{ shape: text, label: "Moyenne des Chiffre d'affaires par client" }
G@{ shape: text, label: "Clients" }-->I["1ère Requête"]
H@{ shape: text, label: "Commandes" }-->I
F-->I
I-->J@{ shape: text, label: "Clients dont le chiffre d'affaires est supérieur à la moyenne" }
```
### Préparation des requêtes
Avant de les écrire, nous vous conseillons de préparer chaque requête pour :
1. Bien comprendre ce que vous faites
2. Ne pas passer trop de temps à taper du code SQL
#### Préparation de la 3ème requête
![[cours01.png|500]]
#### Préparation de la 2ème requête
![[cours02.png|500]]
#### Préparation de la 1ère requête
![[cours03.png|500]]
### Requête finale
``` SQL
SELECT -- Troisième requête : clients dont le CA > CA moyen
C.id_client,
C.nom_client,
SUM(Co.montant_total) AS chiffre_affaires
FROM Clients C
INNER JOIN Commandes Co
ON C.id_client = Co.id_client
,
(
-- Deuxième requête : moyenne du chiffre d’affaires par client
SELECT
AVG(ca_client) AS moyenne_ca
FROM ( -- Première requête : chiffres d'affaires par client
SELECT
SUM(Co2.montant_total) AS ca_client
FROM Clients C2
INNER JOIN Commandes Co2
ON C2.id_client = Co2.id_client
GROUP BY C2.id_client
) AS t
) AS m
GROUP BY
C.id_client,
C.nom_client,
m.moyenne_ca
HAVING
SUM(Co.montant_total) > m.moyenne_ca;
```
Dans le chapitre d'après, nous allons généraliser la lecture du FROM avec plusieurs tables :
[[06_Généralisation_Requête sur n tables]]