PostgreSQL est le SGBD relationnel open source le plus utilisé pour les nouvelles applications web et les plateformes data. Il respecte bien le standard SQL, offre des types riches et un optimiseur performant. Ce cours se base sur PostgreSQL 18 (sorti fin 2025) ; tout ce qui est présenté fonctionne aussi sur les versions récentes antérieures, sauf mention contraire.
Des types précis
CREATE TABLE commandes (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
reference uuid NOT NULL DEFAULT gen_random_uuid() UNIQUE,
client_id bigint NOT NULL REFERENCES clients(id),
montant numeric(10,2) NOT NULL CHECK (montant >= 0),
statut text NOT NULL DEFAULT 'en_attente',
options jsonb NOT NULL DEFAULT '{}',
cree_le timestamptz NOT NULL DEFAULT now()
);
GENERATED ALWAYS AS IDENTITYest la forme standard d’auto-incrément ;serialreste accepté mais n’est plus recommandé.uuiddonne des identifiants non devinables, utiles dans les URL d’une API.gen_random_uuid()produit des UUID v4 ; PostgreSQL 18 ajouteuuidv7(), dont les valeurs croissent avec le temps et s’indexent mieux.numericest exact : indispensable pour l’argent.textn’a pas de pénalité de performance par rapport àvarchar(n); on ajoute unCHECKsi une longueur maximale est une vraie règle métier.timestamptzenregistre un instant (converti en UTC) et l’affiche dans le fuseau de la session (SET TIME ZONE 'Europe/Paris'). Le typetimestampsans fuseau est ambigu dès que plusieurs fuseaux sont en jeu.
JSONB : de la souplesse dans un modèle relationnel
jsonb stocke du JSON sous une forme binaire, indexable. Il est idéal pour des attributs variables (caractéristiques d’un produit, préférences d’un utilisateur), pas pour remplacer des colonnes interrogées en permanence.
SELECT nom,
attributs -> 'taille' AS taille_json, -- résultat jsonb : "M"
attributs ->> 'couleur' AS couleur -- résultat text : noir
FROM produits
WHERE attributs @> '{"couleur": "noir"}'; -- contient cette paire
->> renvoie du texte, à utiliser pour comparer ou afficher ; @> teste l’inclusion et peut utiliser un index GIN (leçon 4). SQLite propose aussi -> et ->> (depuis la version 3.38), ce qui permet de s’entraîner dans le navigateur.
Upsert et RETURNING
Insérer une ligne, ou la mettre à jour si elle existe déjà, se fait en une seule instruction atomique :
INSERT INTO stocks (produit_id, quantite)
VALUES (42, 10)
ON CONFLICT (produit_id) -- exige une contrainte UNIQUE ou PK
DO UPDATE SET quantite = stocks.quantite + EXCLUDED.quantite
RETURNING produit_id, quantite;
EXCLUDED désigne la ligne qu’on tentait d’insérer. ON CONFLICT DO NOTHING ignore simplement les doublons. RETURNING renvoie les lignes écrites (avec leurs valeurs générées : id, cree_le), ce qui évite un SELECT supplémentaire après chaque INSERT. Pour des synchronisations plus complexes, PostgreSQL dispose aussi de MERGE (depuis la version 15).
Premiers pas dans psql
psql est le client en ligne de commande officiel :
psql -h localhost -U app -d boutique -- connexion
\dt -- lister les tables
\d commandes -- structure, index et contraintes d'une table
\x -- affichage étendu (une colonne par ligne)
\timing -- afficher la durée de chaque requête
\q -- quitter
\d et \timing vous serviront dans toute la suite du cours pour vérifier vos index et mesurer vos optimisations.
Exercices
Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.
Filtrer sur un attribut JSON
Table disponible :
produits(id, nom, attributs)oùattributscontient un objet JSON.Affichez le nom des produits dont l’attribut
couleurvautnoir, en utilisant l’opérateur->>.Cet exercice s’exécute en SQLite, dont la syntaxe est ici identique à PostgreSQL.
Données de l'exercice (SQL)
-- En PostgreSQL, attributs serait de type jsonb ; SQLite stocke le JSON en texte CREATE TABLE produits ( id INTEGER PRIMARY KEY, nom TEXT NOT NULL, attributs TEXT NOT NULL ); INSERT INTO produits VALUES (1, 'T-shirt', '{"couleur": "noir", "taille": "M"}'), (2, 'Sweat', '{"couleur": "gris", "taille": "L"}'), (3, 'Casquette', '{"couleur": "noir"}'), (4, 'Chaussettes', '{"taille": "S", "lot": 3}');SELECT nom FROM produits WHERE attributs ->> ... = ...;Répartition par couleur
Table disponible :
produits(id, nom, attributs).Affichez chaque couleur (alias
couleur, avec'non renseignée'quand l’attribut est absent) et le nombre de produits (aliasnb).Cet exercice s’exécute en SQLite, dont la syntaxe est ici identique à PostgreSQL.
Données de l'exercice (SQL)
-- En PostgreSQL, attributs serait de type jsonb ; SQLite stocke le JSON en texte CREATE TABLE produits ( id INTEGER PRIMARY KEY, nom TEXT NOT NULL, attributs TEXT NOT NULL ); INSERT INTO produits VALUES (1, 'T-shirt', '{"couleur": "noir", "taille": "M"}'), (2, 'Sweat', '{"couleur": "gris", "taille": "L"}'), (3, 'Casquette', '{"couleur": "noir"}'), (4, 'Chaussettes', '{"taille": "S", "lot": 3}');SELECT COALESCE(..., 'non renseignée') AS couleur, COUNT(*) AS nb FROM produits GROUP BY ...;Horodater des événements
Une application enregistre l’heure de connexion d’utilisateurs situés en France et au Québec. Quel type choisir ?
- timestamp
- timestamptz
- text au format ISO
Upsert de stock dans psql
Dans une base PostgreSQL de test, créez une table
stocks(produit_id bigint PRIMARY KEY, quantite integer NOT NULL CHECK (quantite >= 0)). Écrivez une instruction unique qui ajoute 10 unités au produit 42, en créant la ligne si elle n’existe pas, et qui renvoie la quantité finale. Exécutez-la deux fois.- La table est créée avec une clé primaire sur produit_id
- L'instruction utilise INSERT ... ON CONFLICT (produit_id) DO UPDATE
- La mise à jour utilise EXCLUDED.quantite pour additionner
- RETURNING renvoie produit_id et quantite
- La première exécution renvoie 10, la seconde 20
Quiz de fin de leçon
Que renvoie attributs ->> ‘taille’ sur une colonne jsonb ?
- Une valeur jsonb
- Une valeur text
- Un booléen
Quelle condition est nécessaire pour INSERT … ON CONFLICT (email) ?
- Un index GIN sur email
- Une contrainte UNIQUE (ou clé primaire) sur email
- Une colonne de type uuid
À quoi sert RETURNING ?
- À annuler une écriture
- À renvoyer les lignes écrites, avec leurs valeurs générées
- À relancer la requête en cas d'erreur
La suite du cours
- Lire un plan d'exécution avec EXPLAIN ANALYZE20 min
- Les index B-tree : créer, composer, rendre utilisables20 min
- Index spécialisés : partiels, expressions, GIN, BRIN18 min
- Optimiser les requêtes et entretenir la base20 min