Aller au contenu

SQL — Cheat Sheet : Manipulation de données⚓︎

Référence rapide pour les opérations DML (Data Manipulation Language) et les requêtes courantes.


Sélection de données⚓︎

SELECT de base⚓︎

SELECT colonne1, colonne2 FROM table;
SELECT * FROM table;
SELECT DISTINCT colonne FROM table;        -- valeurs uniques
SELECT colonne AS alias FROM table;        -- renommer la colonne

Filtrage avec WHERE⚓︎

SELECT * FROM table WHERE colonne = 'valeur';
SELECT * FROM table WHERE age > 18 AND ville = 'Paris';
SELECT * FROM table WHERE statut IN ('actif', 'en_attente');
SELECT * FROM table WHERE nom LIKE 'A%';   -- commence par A
SELECT * FROM table WHERE nom LIKE '%son'; -- finit par "son"
SELECT * FROM table WHERE valeur BETWEEN 10 AND 50;
SELECT * FROM table WHERE colonne IS NULL;
SELECT * FROM table WHERE colonne IS NOT NULL;

Tri et pagination⚓︎

SELECT * FROM table ORDER BY colonne ASC;
SELECT * FROM table ORDER BY colonne DESC;
SELECT * FROM table ORDER BY col1 ASC, col2 DESC;

SELECT * FROM table LIMIT 10;             -- 10 premières lignes
SELECT * FROM table LIMIT 10 OFFSET 20;  -- page 3 (rows 21-30)

Agrégation⚓︎

Fonctions d'agrégat⚓︎

Fonction Description
COUNT(*) Nombre de lignes
COUNT(colonne) Nombre de valeurs non nulles
SUM(colonne) Somme
AVG(colonne) Moyenne
MIN(colonne) Valeur minimale
MAX(colonne) Valeur maximale
SELECT COUNT(*), AVG(salaire), MAX(salaire) FROM employes;

GROUP BY et HAVING⚓︎

-- Grouper les résultats
SELECT departement, COUNT(*) AS nb_employes
FROM employes
GROUP BY departement;

-- Filtrer les groupes (≠ WHERE qui filtre les lignes)
SELECT departement, AVG(salaire) AS salaire_moyen
FROM employes
GROUP BY departement
HAVING AVG(salaire) > 3000;

Ordre d'exécution

WHERE filtre avant le groupement, HAVING filtre après.


Jointures⚓︎

-- INNER JOIN : lignes communes aux deux tables
SELECT u.nom, c.montant
FROM utilisateurs u
INNER JOIN commandes c ON u.id = c.utilisateur_id;

-- LEFT JOIN : toutes les lignes de gauche, nulls à droite si pas de correspondance
SELECT u.nom, c.montant
FROM utilisateurs u
LEFT JOIN commandes c ON u.id = c.utilisateur_id;

-- RIGHT JOIN : toutes les lignes de droite
SELECT u.nom, c.montant
FROM utilisateurs u
RIGHT JOIN commandes c ON u.id = c.utilisateur_id;

-- FULL OUTER JOIN : toutes les lignes des deux tables
SELECT u.nom, c.montant
FROM utilisateurs u
FULL OUTER JOIN commandes c ON u.id = c.utilisateur_id;

-- SELF JOIN : jointure d'une table sur elle-même
SELECT a.nom AS employe, b.nom AS manager
FROM employes a
JOIN employes b ON a.manager_id = b.id;

-- CROSS JOIN : produit cartésien
SELECT * FROM taille CROSS JOIN couleur;

Insertion de données⚓︎

-- Insertion d'une ligne
INSERT INTO utilisateurs (nom, email, age)
VALUES ('Alice', 'alice@example.com', 30);

-- Insertion multiple
INSERT INTO utilisateurs (nom, email, age) VALUES
  ('Bob', 'bob@example.com', 25),
  ('Carol', 'carol@example.com', 28);

-- Insertion depuis une requête
INSERT INTO archive_utilisateurs (nom, email)
SELECT nom, email FROM utilisateurs WHERE actif = false;

Mise à jour de données⚓︎

-- Mettre à jour des lignes
UPDATE utilisateurs
SET email = 'nouveau@example.com', age = 31
WHERE id = 42;

-- Mise à jour avec jointure (PostgreSQL / SQL Server)
UPDATE commandes
SET statut = 'vérifié'
FROM utilisateurs
WHERE commandes.utilisateur_id = utilisateurs.id
  AND utilisateurs.role = 'admin';

Toujours utiliser WHERE

Un UPDATE sans clause WHERE modifie toutes les lignes de la table.


Suppression de données⚓︎

-- Supprimer des lignes filtrées
DELETE FROM utilisateurs WHERE actif = false;

-- Vider une table (supprime toutes les lignes)
DELETE FROM table;       -- supprimable ligne par ligne, transactionnel
TRUNCATE TABLE table;    -- plus rapide, non transactionnel sur certains SGBD

Pas de WHERE = tout supprimer

Vérifier la clause WHERE avant d'exécuter un DELETE.


Sous-requêtes⚓︎

-- Dans WHERE
SELECT nom FROM employes
WHERE salaire > (SELECT AVG(salaire) FROM employes);

-- Avec IN
SELECT nom FROM utilisateurs
WHERE id IN (SELECT utilisateur_id FROM commandes WHERE montant > 500);

-- Sous-requête corrélée
SELECT nom, salaire
FROM employes e1
WHERE salaire > (
  SELECT AVG(salaire) FROM employes e2
  WHERE e2.departement = e1.departement
);

-- Dans FROM (table dérivée)
SELECT dept, salaire_moyen
FROM (
  SELECT departement AS dept, AVG(salaire) AS salaire_moyen
  FROM employes
  GROUP BY departement
) AS stats
WHERE salaire_moyen > 4000;

Expressions de table communes (CTE)⚓︎

-- CTE simple
WITH employes_seniors AS (
  SELECT * FROM employes WHERE anciennete > 5
)
SELECT departement, COUNT(*) FROM employes_seniors
GROUP BY departement;

-- CTE chaînées
WITH
  ventes_2024 AS (
    SELECT * FROM ventes WHERE YEAR(date) = 2024
  ),
  top_produits AS (
    SELECT produit_id, SUM(montant) AS total
    FROM ventes_2024
    GROUP BY produit_id
    HAVING SUM(montant) > 10000
  )
SELECT p.nom, t.total
FROM top_produits t
JOIN produits p ON t.produit_id = p.id;

-- CTE récursive (ex: hiérarchie)
WITH RECURSIVE hierarchie AS (
  SELECT id, nom, manager_id, 0 AS niveau
  FROM employes WHERE manager_id IS NULL

  UNION ALL

  SELECT e.id, e.nom, e.manager_id, h.niveau + 1
  FROM employes e
  JOIN hierarchie h ON e.manager_id = h.id
)
SELECT * FROM hierarchie ORDER BY niveau;

Fonctions de fenêtrage⚓︎

-- Numérotation
SELECT nom, salaire,
  ROW_NUMBER() OVER (ORDER BY salaire DESC) AS rang,
  RANK()       OVER (ORDER BY salaire DESC) AS rang_ex_aequo,
  DENSE_RANK() OVER (ORDER BY salaire DESC) AS rang_dense
FROM employes;

-- Partitionnement
SELECT nom, departement, salaire,
  RANK() OVER (PARTITION BY departement ORDER BY salaire DESC) AS rang_dept
FROM employes;

-- Agrégats glissants
SELECT date, montant,
  SUM(montant) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS total_7j,
  AVG(montant) OVER (PARTITION BY MONTH(date)) AS moy_mensuelle
FROM ventes;

-- Décalage
SELECT date, montant,
  LAG(montant, 1)  OVER (ORDER BY date) AS montant_precedent,
  LEAD(montant, 1) OVER (ORDER BY date) AS montant_suivant
FROM ventes;

Manipulation de chaînes⚓︎

UPPER(str)                -- 'hello' → 'HELLO'
LOWER(str)                -- 'HELLO' → 'hello'
LENGTH(str)               -- longueur
TRIM(str)                 -- supprime les espaces en début/fin
LTRIM(str) / RTRIM(str)
SUBSTRING(str, 1, 3)      -- extrait 3 caractères depuis la position 1
CONCAT(a, ' ', b)         -- concaténation
REPLACE(str, 'a', 'b')    -- remplace toutes les occurrences
POSITION('sub' IN str)    -- position de la sous-chaîne
COALESCE(col, 'défaut')   -- retourne la première valeur non nulle

Manipulation de dates⚓︎

NOW() / CURRENT_TIMESTAMP  -- date et heure actuelles
CURRENT_DATE               -- date du jour
CURRENT_TIME               -- heure actuelle

DATE_ADD(date, INTERVAL 7 DAY)   -- MySQL
date + INTERVAL '7 days'          -- PostgreSQL

DATEDIFF(date1, date2)     -- différence en jours (MySQL)
date1 - date2              -- différence en jours (PostgreSQL)

EXTRACT(YEAR FROM date)    -- extraire l'année
DATE_FORMAT(date, '%Y-%m') -- formater (MySQL)
TO_CHAR(date, 'YYYY-MM')   -- formater (PostgreSQL)

Opérations sur les ensembles⚓︎

-- Union (dédoublonnée)
SELECT nom FROM clients
UNION
SELECT nom FROM fournisseurs;

-- Union avec doublons
SELECT nom FROM clients
UNION ALL
SELECT nom FROM fournisseurs;

-- Intersection
SELECT nom FROM clients
INTERSECT
SELECT nom FROM fournisseurs;

-- Différence
SELECT nom FROM clients
EXCEPT               -- PostgreSQL / SQL Server
SELECT nom FROM fournisseurs;
-- ou MINUS sur Oracle

Expressions conditionnelles⚓︎

-- CASE simple
SELECT nom,
  CASE statut
    WHEN 'A' THEN 'Actif'
    WHEN 'I' THEN 'Inactif'
    ELSE 'Inconnu'
  END AS libelle_statut
FROM utilisateurs;

-- CASE recherché
SELECT nom, salaire,
  CASE
    WHEN salaire < 2000 THEN 'Bas'
    WHEN salaire < 4000 THEN 'Moyen'
    ELSE 'Élevé'
  END AS tranche
FROM employes;

-- Raccourcis
COALESCE(a, b, c)        -- premier non NULL
NULLIF(a, b)             -- NULL si a = b, sinon a
IIF(condition, a, b)     -- SQL Server uniquement

Transactions⚓︎

BEGIN;                   -- ou START TRANSACTION

UPDATE comptes SET solde = solde - 100 WHERE id = 1;
UPDATE comptes SET solde = solde + 100 WHERE id = 2;

COMMIT;                  -- valider
-- ou
ROLLBACK;                -- annuler

-- Point de sauvegarde
SAVEPOINT mon_point;
ROLLBACK TO mon_point;
RELEASE SAVEPOINT mon_point;

Propriétés ACID

Une transaction garantit Atomicité, Cohérence, Isolation et Durabilité.


Bonnes pratiques⚓︎

  • Toujours tester un UPDATE / DELETE avec un SELECT équivalent d'abord.
  • Utiliser des transactions pour les opérations multi-étapes critiques.
  • Préférer les CTEs aux sous-requêtes imbriquées pour la lisibilité.
  • Éviter SELECT * en production — nommer les colonnes explicitement.
  • Indexer les colonnes utilisées dans WHERE, JOIN ON et ORDER BY.
  • Utiliser EXPLAIN / EXPLAIN ANALYZE pour diagnostiquer les performances.
EXPLAIN ANALYZE
SELECT u.nom, COUNT(c.id)
FROM utilisateurs u
LEFT JOIN commandes c ON u.id = c.utilisateur_id
GROUP BY u.nom;