</>
Plan du cours — 17/64

Contraintes : NOT NULL, UNIQUE, CHECK, EXCLUDE

Intermédiaire

Plus une règle est près des données, moins elle peut être contournée : une contrainte protège contre tous les clients de la base, pas seulement votre application.

CREATE TABLE produits (
    id        bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    sku       text           NOT NULL UNIQUE,
    prix      numeric(12, 2) NOT NULL CHECK (prix >= 0),
    stock     integer        NOT NULL DEFAULT 0 CHECK (stock >= 0),
    statut    text           NOT NULL CHECK (statut IN ('brouillon', 'publie', 'archive'))
);

Unicité partielle et sur plusieurs colonnes#

-- Un seul compte actif par email (les comptes supprimés sont ignorés)
CREATE UNIQUE INDEX comptes_email_actif_idx ON comptes (email) WHERE supprime_le IS NULL;

-- Unicité d'un couple
ALTER TABLE inscriptions ADD CONSTRAINT inscription_unique UNIQUE (utilisateur_id, cours_id);

EXCLUDE : empêcher les chevauchements#

CREATE EXTENSION IF NOT EXISTS btree_gist;

CREATE TABLE reservations (
    salle_id int       NOT NULL,
    periode  tstzrange NOT NULL,
    EXCLUDE USING gist (salle_id WITH =, periode WITH &&)   -- même salle : pas de périodes qui se chevauchent
);

Cas pratique : une contrainte EXCLUDE sur une plage de temps interdit les doubles réservations sans verrou applicatif ni condition de course : deux transactions concurrentes qui tentent de réserver la même salle sur des périodes qui se chevauchent verront l'une des deux échouer.