Intro SQL : ta passerelle vers les données
Lire, filtrer, croiser et modifier des données avec SQL. Les bases solides pour comprendre une base relationnelle et écrire tes premières requêtes utiles.
À la fin du cours, tu sais
- Comprendre comment les données s'organisent en tables et relations
- Écrire des SELECT avec filtres, tri, pagination
- Insérer, modifier et supprimer des données proprement
- Croiser plusieurs tables avec les jointures
- Agréger pour répondre à des questions métier (COUNT, SUM, GROUP BY)
Prérequis
- Être à l'aise avec un terminal
- Avoir installé PostgreSQL ou MySQL en local (Docker fait l'affaire)
Étape 1 sur 10 : Pourquoi SQL et où ça vit
Chapitre 1
Pourquoi SQL et où ça vit
SQL est le langage standard pour interroger les bases relationnelles. C'est l'outil que tu vas croiser dans 90 % des projets back-end.
SQL est le langage standard pour dialoguer avec les bases de données relationnelles, et c'est l'un des rares outils que tu croiseras dans la quasi-totalité des projets, quel que soit le langage de programmation. Que tu écrives ton back-end en JavaScript, en Python, en Java ou en PHP, tôt ou tard tu parles à ta base en SQL. Bonne nouvelle : c'est un langage remarquablement stable — celui que tu apprends aujourd'hui fonctionnera encore dans vingt ans — et déclaratif : tu décris ce que tu veux, pas comment l'obtenir, et le moteur se charge du reste.
Concrètement, SQL te sert dans quatre situations très différentes. Il te permet de lire des données pour les afficher dans une application, d'écrire des migrations et de faire évoluer la structure de ta base, d'exécuter des scripts d'analyse, de nettoyage ou de débogage directement en production, et de comprendre ce que fait un ORM (comme Prisma, Sequelize ou TypeORM) sous le capot. Ce dernier point est capital : même si un framework génère le SQL à ta place, savoir lire ce qu'il produit fait la différence le jour où une requête est lente ou renvoie un résultat inattendu.
Il est aussi utile de situer SQL face au NoSQL. Le relationnel brille quand tu as un schéma stable, des relations claires entre tes données et un besoin de transactions fiables (le fameux principe ACID, qui garantit qu'une opération passe entièrement ou pas du tout). Le NoSQL vise plutôt des données très hétérogènes, un schéma qui change en permanence ou un passage à l'échelle horizontal massif. La réalité du terrain est qu'environ 80 % des projets sont mieux servis par une base relationnelle — c'est le choix par défaut le plus sûr, et donc celui par lequel il faut commencer.
Le rôle du SQL dans ton stack
- Lire des données pour les afficher dans une app
- Écrire des migrations et manipuler le schéma
- Faire des scripts d'analyse, de cleanup, de debug en prod
- Comprendre ce que fait un ORM (Sequelize, Prisma, TypeORM) sous le capot
Moteurs et clients
- Moteur (serveur) : PostgreSQL 16 ou MySQL 8 sont les références. SQLite pour le local léger.
- Client :
psql,mysql, ou GUI comme DBeaver, TablePlus, Postico - Tout passe par TCP/IP entre client et serveur (sauf SQLite, fichier local)
SQL vs NoSQL : quand choisir quoi
SQL : tu as un schéma stable, des relations claires, besoin de transactions ACID. NoSQL : données très hétérogènes, scaling horizontal massif, schéma qui change tout le temps. 80 % des projets sont mieux servis par du SQL.
psql -U postgres -d mabase
# Une fois dedans :
\dt # liste les tables
\d utilisateurs # décrit une table
SELECT version();
\q # quitterChapitre 2
Modèle relationnel et types de données
Avant d'écrire une requête, comprendre comment les données sont structurées. La force du relationnel : tout est table.
Avant d'écrire la moindre requête, il faut comprendre comment les données sont organisées, car c'est cette structure qui rend SQL si puissant. Toute la force du modèle relationnel tient dans une idée unique : tout est table. Une table est un tableau à deux dimensions — des colonnes qui définissent des attributs, des lignes qui contiennent les données. Une table représente une entité de ton métier (les utilisateurs, les commandes, les produits), chaque colonne est un attribut typé (un identifiant, un email, un prix), et chaque ligne est une occurrence précise (un utilisateur donné).
Deux notions structurent les relations entre tables. La clé primaire (PK) identifie de façon unique chaque ligne d'une table — c'est presque toujours un identifiant technique auto-incrémenté. La clé étrangère (FK) est une colonne qui pointe vers la clé primaire d'une autre table : c'est ainsi qu'on relie une commande à son client, sans dupliquer les informations du client dans chaque commande. Ce jeu de clés est le cœur du relationnel : il évite la redondance et garantit la cohérence.
Le choix du bon type pour chaque colonne n'est pas un détail, et une erreur ici se paie cher plus tard. Les entiers (INTEGER, BIGINT), les chaînes (VARCHAR, TEXT), les booléens, les dates (TIMESTAMP, DATE) couvrent l'essentiel. Une règle à retenir absolument : pour de l'argent, utilise NUMERIC et jamais FLOAT, car les nombres à virgule flottante introduisent des erreurs d'arrondi (le fameux 0.1 + 0.2 qui ne fait pas exactement 0.3). Enfin, on pose des contraintes dès la création de la table (NOT NULL, UNIQUE, CHECK) : elles empêchent la base d'accepter des données incohérentes, ce qui vaut bien mieux que de découvrir le problème une fois les données corrompues.
Tables, colonnes, lignes
- Table : une entité (utilisateurs, commandes, produits)
- Colonne : un attribut typé (id, email, prix)
- Ligne : une instance (un utilisateur précis)
- Clé primaire (PK) : identifie une ligne de façon unique
- Clé étrangère (FK) : pointe vers la PK d'une autre table
Les types essentiels
INTEGER,BIGINT: entiersNUMERIC(10,2): décimaux précis (utilise-le pour de l'argent, pasFLOAT)VARCHAR(255),TEXT: chaînes de caractèresBOOLEAN: true / falseTIMESTAMP,DATE: datesJSONB(Postgres) : JSON avec indexation possible
Contraintes utiles dès la création
CREATE TABLE utilisateurs (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
prenom VARCHAR(100),
age INTEGER CHECK (age >= 0),
cree_le TIMESTAMP NOT NULL DEFAULT NOW()
);NUMERIC pour l'argent, toujours
FLOAT et DOUBLE font des erreurs d'arrondi. NUMERIC(10,2) garantit 10 chiffres avec 2 décimales exactes. Indispensable dès qu'il s'agit d'euros.Chapitre 3
SELECT : le couteau suisse
La lecture, c'est 80 % de ton usage SQL au quotidien. Les variations sont infinies, mais 5 mots-clés couvrent l'essentiel.
Si tu ne devais maîtriser qu'une seule commande SQL, ce serait SELECT : la lecture représente à elle seule environ 80 % de ton usage quotidien. La bonne nouvelle, c'est que malgré des variations infinies, sa structure de base tient en cinq mots-clés qui s'enchaînent toujours dans le même ordre : SELECT (quelles colonnes), FROM (quelle table), WHERE (quelles conditions), ORDER BY (quel tri), LIMIT (combien de lignes). Une fois cette ossature en tête, tu peux lire et écrire l'écrasante majorité des requêtes que tu rencontreras.
Le vrai travail se joue souvent dans le WHERE, qui filtre les lignes. Au-delà des comparaisons classiques, quelques opérateurs reviennent sans cesse : IN (...) pour tester l'appartenance à une liste, BETWEEN ... AND ... pour une plage, LIKE avec les jokers % (n'importe quelle suite de caractères) et _ (un seul caractère) pour les recherches textuelles. Une subtilité qui piège tous les débutant·es : les valeurs nulles ne se testent jamais avec = NULL (qui ne renvoie jamais vrai) mais avec IS NULL et IS NOT NULL. Ajoute ORDER BY pour trier, LIMIT et OFFSET pour paginer, et tu couvres déjà la plupart des besoins d'affichage.
Un dernier réflexe, plus discret mais important en production : évite le SELECT * dans le code de ton application. Pratique en exploration, il devient dangereux dans une application réelle — le jour où quelqu'un ajoute une colonne à la table, ta requête ramène des données inutiles, voire fait planter ton code qui ne s'y attendait pas. Liste explicitement les colonnes dont tu as besoin : c'est plus clair, plus stable, et souvent plus rapide. Cette exigence de précision distingue une requête d'exploration d'une requête destinée à vivre en production, comme tu pourras t'en rendre compte dans l'éditeur SQL interactif de ce chapitre.
La structure de base
SELECT colonnes
FROM table
WHERE conditions
ORDER BY colonne
LIMIT n;Filtrer avec WHERE
SELECT email, prenom
FROM utilisateurs
WHERE age >= 18
AND email LIKE '%@gmail.com'
AND cree_le BETWEEN '2026-01-01' AND '2026-12-31';=,<>(différent),<,>,<=,>=IN (...): appartient à une listeBETWEEN ... AND ...: plage inclusiveLIKEavec%(n'importe quoi) ou_(un caractère)IS NULL/IS NOT NULL(jamais= NULL, ça ne marche pas)
Trier et paginer
-- Les 20 derniers inscrits
SELECT email, cree_le
FROM utilisateurs
ORDER BY cree_le DESC
LIMIT 20;
-- Pagination : page 3 (20 par page)
SELECT email FROM utilisateurs
ORDER BY id
LIMIT 20 OFFSET 40;Alias et DISTINCT
-- Renommer dans le résultat
SELECT email AS adresse, prenom AS nom
FROM utilisateurs;
-- Valeurs uniques
SELECT DISTINCT pays FROM clients;SELECT * en prod, à éviter
SELECT * est pratique en exploration mais dangereux en code applicatif : un ALTER TABLE ADD COLUMN et ton app crashe ou ramène des colonnes inutiles. Liste explicitement les colonnes dont tu as besoin.Vrai ou faux ?
Dans un LIKE, le caractère % remplace n'importe quelle suite de caractères, alors que _ remplace exactement un seul caractère.
🛢️ À toi : écris du vrai SQL
Une vraie base SQLite tourne dans ton navigateur. Modifie la requête, clique sur Exécuter, regarde le résultat. Tu ne peux rien casser : « Réinitialiser » remet tout à zéro.
À toi de jouer
- Affiche seulement les client·es de France (
WHERE pays = 'France'). - Trie du plus récemment inscrit au plus ancien (
ORDER BY inscrit_le DESC). - Compte le nombre de pays différents (
SELECT COUNT(DISTINCT pays) FROM clients).
Charge SQLite dans ton navigateur (≈ 645 Ko). Rien n'est envoyé à un serveur.
Pour aller plus loin sur SELECT
- SELECT et les bases du langage (en français) · sql.sh (nouvel onglet)
- Documentation officielle : la commande SELECT · postgresql.org (en anglais) (nouvel onglet)
- Premiers pas avec les requêtes SQL · MDN (en anglais) (nouvel onglet)
Chapitre 4
Écrire et modifier les données
INSERT, UPDATE, DELETE : les commandes qui modifient ta base. Le réflexe à avoir : toujours un WHERE.
Lire des données ne suffit pas : tôt ou tard, tu dois les modifier. Trois commandes s'en chargent, et elles forment un trio à respecter avec sérieux car elles changent réellement l'état de ta base. INSERT ajoute de nouvelles lignes, UPDATE modifie des lignes existantes, DELETE en supprime. Là où un SELECT raté ne fait que renvoyer un mauvais résultat, un UPDATE ou un DELETE raté abîme durablement tes données.
D'où le réflexe de survie numéro un : toujours écrire le WHERE en premier. Un UPDATE utilisateurs SET actif = false lancé sans WHERE ne met pas à jour une ligne, mais toutes les lignes de la table — une catastrophe classique et irréversible. Prends l'habitude de taper d'abord ta condition de filtre, de vérifier qu'elle cible bien ce que tu veux (au besoin avec un SELECT de contrôle), puis seulement d'ajouter le SET. Ce simple ordre de frappe t'évitera un jour une très mauvaise surprise en production.
Quand plusieurs modifications doivent aller ensemble, on les regroupe dans une transaction. Encadrée par BEGIN et COMMIT, une transaction rend un ensemble d'opérations indivisible : soit tout réussit, soit — en cas de problème — un ROLLBACK annule tout et la base reste cohérente. L'exemple typique est un virement bancaire : débiter un compte et créditer l'autre doivent réussir ou échouer ensemble, jamais à moitié. Attention toutefois : une fois le COMMIT passé, c'est définitif — ROLLBACK n'a plus d'effet. Tu ne peux annuler que tant que la transaction est ouverte.
INSERT
-- Une ligne
INSERT INTO utilisateurs (email, prenom)
VALUES ('alice@exemple.fr', 'Alice');
-- Plusieurs lignes d'un coup
INSERT INTO utilisateurs (email, prenom) VALUES
('bob@exemple.fr', 'Bob'),
('clara@exemple.fr', 'Clara');
-- Retourner la ligne insérée (Postgres)
INSERT INTO utilisateurs (email) VALUES ('dan@exemple.fr')
RETURNING id, cree_le;UPDATE
UPDATE utilisateurs
SET prenom = 'Alice', age = 28
WHERE email = 'alice@exemple.fr';UPDATE sans WHERE = catastrophe
WHERE, tu modifies toutes les lignes de la table. Réflexe absolu : commence toujours par écrire le WHERE, puis ajoute le SET.DELETE
DELETE FROM utilisateurs WHERE id = 42;
-- Vider toute la table (utilise TRUNCATE plutôt, plus rapide)
TRUNCATE utilisateurs RESTART IDENTITY CASCADE;Transactions
Une transaction groupe plusieurs opérations en un tout indivisible : soit tout passe (COMMIT), soit rien (ROLLBACK).
BEGIN;
UPDATE comptes SET solde = solde - 100 WHERE id = 1;
UPDATE comptes SET solde = solde + 100 WHERE id = 2;
COMMIT;
-- Si ça plante au milieu : ROLLBACK et la base reste cohérenteVrai ou faux ?
Un DELETE validé peut toujours s'annuler avec ROLLBACK, même après COMMIT.
Chapitre 5
Jointures : croiser plusieurs tables
Le vrai pouvoir du relationnel. Tu connectes des tables liées par des clés étrangères pour répondre à des questions métier.
Les jointures sont le véritable pouvoir du modèle relationnel, et le moment où SQL devient vraiment intéressant. Puisque les données sont réparties dans plusieurs tables reliées par des clés étrangères, il faut pouvoir les recroiser pour répondre à des questions métier : « quels produits a commandés tel client ? », « quel est le chiffre d'affaires par région ? ». Une jointure connecte deux tables sur une condition de correspondance (typiquement, la clé étrangère d'un côté égale la clé primaire de l'autre) et te renvoie un résultat combiné.
Quatre types de jointures couvrent l'essentiel, mais deux suffisent au quotidien. L'INNER JOIN ne garde que les lignes ayant une correspondance des deux côtés : les clients qui ont passé des commandes. Le LEFT JOIN garde toutes les lignes de la table de gauche, en remplissant par NULL quand il n'y a pas de correspondance à droite : tous les clients, avec ou sans commande. Le RIGHT JOIN est l'inverse du LEFT (rare, on préfère inverser les tables), et le FULL OUTER JOIN garde tout des deux côtés. Comprendre la différence entre INNER et LEFT, c'est déjà savoir répondre à la majorité des besoins.
Un motif mérite d'être mémorisé car il revient partout : l'anti-jointure. Le pattern LEFT JOIN ... WHERE table_droite.id IS NULL trouve précisément les lignes de gauche qui n'ont aucune correspondance à droite — les clients sans commande, les produits jamais vendus, les comptes sans activité. C'est l'outil idéal pour les audits, les relances marketing ou le nettoyage de données. Et lorsque plusieurs tables sont impliquées, on enchaîne simplement les jointures. Une garantie te protège au passage : si tu as bien déclaré tes clés étrangères, la base t'empêche de créer des données orphelines qui rendraient ces jointures incohérentes. Le scénario ci-dessous te fait justement retrouver, pas à pas, les clients sans commande.
Les jointures fondamentales
- INNER JOIN : seulement les lignes qui ont une correspondance des deux côtés
- LEFT JOIN : toutes les lignes de gauche, avec NULL à droite si pas de correspondance
- RIGHT JOIN : l'inverse (rare en pratique, on inverse les tables)
- FULL OUTER JOIN : toutes les lignes des deux côtés
SELECT u.email, c.id AS commande_id, c.total
FROM utilisateurs u
LEFT JOIN commandes c ON c.utilisateur_id = u.id
ORDER BY u.email, c.id;Trouver les utilisateurs sans commande
SELECT u.email
FROM utilisateurs u
LEFT JOIN commandes c ON c.utilisateur_id = u.id
WHERE c.id IS NULL;L'anti-jointure
LEFT JOIN ... WHERE x.id IS NULL est ultra-courant : il trouve ce qui n'a pas de correspondance. Utile pour des audits ou du cleanup.Plusieurs jointures enchaînées
SELECT u.email, c.id AS commande_id, p.nom AS produit
FROM utilisateurs u
INNER JOIN commandes c ON c.utilisateur_id = u.id
INNER JOIN lignes_commande lc ON lc.commande_id = c.id
INNER JOIN produits p ON p.id = lc.produit_id
WHERE u.email = 'alice@exemple.fr';🧭 Mission : retrouver les clients sans commande
On te demande la liste des clients qui n'ont jamais rien commandé, pour une relance marketing. Quelle approche tu prends ?
La table clients a une PK id, la table commandes a une FK client_id. Comment tu attaques le problème ?
Chapitre 6
Agréger : transformer des lignes en chiffres
COUNT, SUM, AVG, GROUP BY : tu passes de liste de transactions à chiffre d'affaires par client.
L'agrégation, c'est l'art de transformer une liste de lignes en chiffres. Passer d'une liste de transactions au chiffre d'affaires par client, d'une table d'utilisateurs au nombre d'inscriptions par mois : c'est exactement ce que font les fonctions d'agrégation. Les cinq à connaître sont COUNT (compter), SUM (additionner), AVG (moyenne), MIN et MAX. Une nuance utile : COUNT(*) compte toutes les lignes, tandis que COUNT(colonne) ne compte que les valeurs non nulles de cette colonne.
Ces fonctions prennent tout leur sens couplées à GROUP BY, qui regroupe les lignes par catégorie avant d'appliquer le calcul. « Le chiffre d'affaires par client » se traduit par un SUM(total) avec un GROUP BY client_id : le moteur constitue un groupe par client, puis calcule la somme dans chaque groupe. C'est le mécanisme qui alimente la plupart des tableaux de bord et des rapports que tu construiras. Tu peux ensuite trier ces résultats agrégés avec ORDER BY pour, par exemple, classer tes clients du plus au moins dépensier.
Reste une distinction que beaucoup confondent : WHERE contre HAVING. WHERE filtre les lignes avant le regroupement — il agit sur les données brutes. HAVING filtre les groupes après le calcul d'agrégat — il agit sur les résultats. « Les clients ayant dépensé plus de 1000 € en 2026 » combine les deux : un WHERE pour ne garder que les commandes de 2026, puis un HAVING SUM(total) > 1000 pour ne conserver que les groupes dont la somme dépasse le seuil. Retenir que WHERE agit sur les lignes et HAVING sur les groupes t'évite l'une des erreurs les plus fréquentes en SQL.
Les fonctions d'agrégation
COUNT(*): nombre de lignesCOUNT(colonne): nombre de valeurs non NULLSUM(colonne): sommeAVG(colonne): moyenneMIN(colonne),MAX(colonne): min et max
GROUP BY : regrouper par catégorie
-- CA par utilisateur·ice
SELECT utilisateur_id, SUM(total) AS ca, COUNT(*) AS nb_commandes
FROM commandes
GROUP BY utilisateur_id
ORDER BY ca DESC;WHERE vs HAVING
WHERE filtre avant le regroupement (sur les lignes). HAVING filtre après le regroupement (sur les agrégats).
SELECT utilisateur_id, SUM(total) AS ca
FROM commandes
WHERE cree_le >= '2026-01-01' -- filtre des lignes
GROUP BY utilisateur_id
HAVING SUM(total) > 1000; -- filtre des groupesChapitre 7
Performance et sécurité
Trois réflexes pour éviter les ennuis : indexer ce qui se filtre, utiliser EXPLAIN, et ne jamais concaténer des entrées utilisateur dans une requête.
Écrire une requête qui donne le bon résultat est une chose ; écrire une requête qui reste rapide et sûre en est une autre. Ce dernier chapitre te donne trois réflexes qui font la différence entre du SQL de débutant·e et du SQL de professionnel·le : indexer ce qu'on filtre, lire les plans d'exécution, et ne jamais concaténer d'entrée utilisateur dans une requête. Aucun n'est compliqué, mais chacun t'évite une catégorie entière de problèmes.
Un index est une structure de données annexe qui accélère la recherche, comme l'index d'un livre t'évite de le lire en entier pour trouver un mot. Sans index, filtrer sur une colonne oblige le moteur à parcourir toute la table (un Sequential Scan) ; avec un index sur cette colonne, il va droit au but (un Index Scan). On crée donc des index sur les colonnes qu'on filtre (WHERE) ou qu'on joint (JOIN) souvent. Attention cependant à ne pas en abuser : chaque index doit être maintenu à jour, ce qui ralentit légèrement les INSERT et UPDATE. On indexe ce qui en vaut la peine, pas tout par réflexe. Pour savoir si un index sert, la commande EXPLAIN ANALYZE te montre le plan d'exécution réel : un Seq Scan sur une grosse table est le signal qu'un index manque.
Le troisième réflexe touche à la sécurité, et il est non négociable. Construire une requête en collant directement une entrée utilisateur dedans ouvre la porte à l'injection SQL : un attaquant peut alors glisser du code qui contourne ta logique, lit des données interdites, voire détruit ta base. La parade est universelle et supportée par tous les langages : les requêtes paramétrées (ou préparées). Tu écris la requête avec des emplacements ($1, ?) et tu passes les valeurs séparément ; le moteur sait alors qu'un paramètre est toujours une donnée, jamais du code exécutable, quel que soit son contenu. C'est la même leçon que celle du cours OWASP : on ne concatène jamais, on paramètre toujours.
Index : accélérer les recherches
-- Sans index, ce filtre fait un Sequential Scan
SELECT * FROM commandes WHERE utilisateur_id = 42;
-- On crée un index
CREATE INDEX idx_commandes_utilisateur ON commandes(utilisateur_id);
-- Désormais : Index Scan, beaucoup plus rapideIndex = structure de données séparée qui accélère les recherches. Crée des index sur les colonnes filtrées (WHERE) ou jointes (JOIN). Mais attention : chaque index ralentit les INSERT et UPDATE. Ne mets pas d'index partout sans raison.
EXPLAIN : lire un plan
EXPLAIN ANALYZE
SELECT * FROM commandes WHERE utilisateur_id = 42;Si tu vois Seq Scan sur une grosse table, c'est qu'un index manque. Index Scan = bon signe. Bitmap Heap Scan = aussi correct pour les filtres larges.
Injections SQL : la base à ne jamais oublier
Jamais de concaténation
// Requête paramétrée : sûr
await client.query(
'SELECT * FROM utilisateurs WHERE email = $1',
[emailFourniParUser]
);// Concaténation : vulnérable à l'injection
await client.query(
`SELECT * FROM utilisateurs WHERE email = '${emailFourniParUser}'`
);🛠️ Exercice optionnel
Construire et interroger une mini-boutique
Tu vas modéliser une mini-boutique avec deux tables, y mettre des données, et répondre à des questions métier classiques.
Ta mission
- Crée les tables
clientsetcommandesavec les bonnes contraintes (PK, FK, NOT NULL). - Insère 3 clients (dont au moins 1 à Lyon) et 5 commandes (dont au moins 1 client sans commande).
- Liste les clients de Lyon.
- Calcule le chiffre d'affaires total par client, trié décroissant.
- Trouve les clients qui n'ont jamais commandé (anti-jointure).
- Crée un index pertinent sur
commandes.client_idet lanceEXPLAIN ANALYZEsur la requête du point 4 pour voir l'impact.
Tu bloques ? Des indices, à dévoiler quand tu en as besoin.
Indice 1
Indice masqué.
Indice 2
Indice masqué.
Indice 3
Indice masqué.
✅ QCM de fin de cours
Teste tes acquis
10 questions, plusieurs réponses parfois possibles. Coche tout ce qui te semble juste, puis valide pour voir ton score et les explications.
- 1
Quelle clause filtre des lignes avant agrégation ?
- 2
Que fait un
LEFT JOIN? - 3
Quel type est adapté à un montant en euros ?
- 4
Comment éviter une injection SQL ?
- 5
Que renvoie
COUNT(*)? - 6
Quelle commande supprime toutes les lignes mais garde la structure de la table ?
- 7
À quoi sert
EXPLAIN ANALYZE? - 8
Une clé étrangère garantit quoi ?
- 9
Que se passe-t-il si tu lances
UPDATE utilisateurs SET actif = falsesans WHERE ? - 10
Comment t'assurer que ton
SELECTretourne des lignes uniques ?
Tu peux laisser des questions sans réponse, elles compteront comme fausses.
🎓 Attestation
Ton attestation de réussite
Termine le QCM avec au moins 80% de bonnes réponses pour débloquer ton attestation de réussite.
Tu veux ce cours pour ton équipe ?
Je peux adapter et animer ce cours pour tes formateur·ices ou tes apprenant·es, en présentiel ou en distanciel. Parlons-en pendant l'audit gratuit.
Réserver un audit gratuit →