NOT NULL : Empêche l'enregistrement de valeurs nulles dans une colonne. UNIQUE : Assure que toutes les valeurs dans une colonne sont uniques. PRIMARY KEY : Définit une ou plusieurs colonnes comme clé primaire, garantissant l'unicité
et
servant d'identifiant pour chaque ligne. FOREIGN KEY : Garantit la validité des relations entre plusieurs tables en établissant un
lien
entre une clé primaire et une clé étrangère. CHECK : Vérifie qu'une condition logique est respectée. CREATE TABLE IF NOT EXISTS Employe (
id BIGSERIAL PRIMARY KEY,
prenom VARCHAR(50) NOT NULL,
nom VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
CONSTRAINT uq_prenom_nom UNIQUE (prenom, nom)
);
Cet exemple impose qu'une combinaison de "prenom" et "nom" soit unique dans la table "Employe". Cela peut être utilisé pour éviter des doublons où des personnes auraient le même prénom et nom.
CHECK et FOREIGN KEY sont des contraintes natives
(implémentées par le SGBD).Bien que ces contraintes améliorent la sécurité et la fiabilité des données, il est important de prendre en compte leur impact sur les performances, surtout pour les opérations massives d'insertion ou de modification.
BEGIN;
INSERT INTO Personne (nom, age, email)
VALUES ('Alice', -25, 'alice@example.com'); -- échoue
ROLLBACK; -- annule l'opération
Dans cet exemple, la tentative d'insertion échoue en raison de la contrainte CHECK sur l'âge. L'utilisation d'une transaction permet d'annuler automatiquement toute modification de la base de données.
Exemple : Validation de la syntaxe d'une adresse email dans une application Java avant de l'insérer dans une base de données. Cette validation est utile, mais elle ne remplace pas une contrainte UNIQUE dans la base.
CREATE TABLE IF NOT EXISTS Personne (
id BIGSERIAL PRIMARY KEY,
nom VARCHAR(50) NOT NULL,
age INTEGER CONSTRAINT chk_age CHECK (age >= 0),
email VARCHAR(100) CONSTRAINT uq_email UNIQUE
);
Cette table "Personne" impose des contraintes pour garantir que chaque personne a un identifiant unique, un nom obligatoire, un âge positif, et une adresse email unique.
CREATE TABLE IF NOT EXISTS Commande (
id_commande BIGSERIAL CONSTRAINT pk_commande PRIMARY KEY,
id_client INTEGER NOT NULL,
CONSTRAINT fk_commande_client FOREIGN KEY (id_client)
REFERENCES Client(id) ON DELETE CASCADE
);
DELETE FROM Client WHERE id = 1; -- supprime également les commandes liées
Ici, la suppression d'un client dans la table "Client" entraîne la suppression automatique des
commandes associées dans la table "Commande" grâce à l'option
on delete cascade.
CREATE TABLE IF NOT EXISTS Commande (
id_commande BIGSERIAL CONSTRAINT pk_commande PRIMARY KEY,
id_client INTEGER NOT NULL,
CONSTRAINT fk_commande_client FOREIGN KEY (id_client)
REFERENCES Client(id) ON UPDATE CASCADE ON DELETE CASCADE
);
UPDATE Client
SET id = 2 WHERE id = 1; -- met également à jour l'id dans la table "Commande"
Ici, toute mise à jour de la colonne "id" dans la table "Client" sera répercutée
automatiquement dans la table "Commande" grâce à l'option
on update cascade.
CREATE TABLE IF NOT EXISTS Employe (
id BIGSERIAL PRIMARY KEY,
salaire DECIMAL NOT NULL CONSTRAINT chk_salaire
CHECK (salaire > 0 AND salaire < 10000)
);
Cette contrainte garantit que le salaire des employés est compris entre 0 et 10 000, empêchant l'insertion de valeurs négatives ou excessivement élevées.
CREATE SEQUENCE IF NOT EXISTS seq_personne
START WITH 100
INCREMENT BY 10
MAXVALUE 1000
CYCLE;
Cette séquence commence à 100, incrémente de 10 à chaque appel, et reprend à 100 lorsque la
valeur maximale de 1000 est atteinte (grâce à l'option cycle).
CREATE SEQUENCE seq_personne;
SELECT nextval('seq_personne'); -- génère la prochaine valeur
SELECT currval('seq_personne'); -- renvoie la dernière valeur générée
L'ordre nextval génère la prochaine valeur dans la séquence, tandis que
currval renvoie la
dernière valeur générée par nextval. Ces commandes sont essentielles pour l'insertion
d'enregistrements avec
des identifiants uniques dans des systèmes multi-utilisateurs.
INSERT INTO Personne (id, nom, age, email)
VALUES (nextval('seq_personne'), 'Alice', 30, 'alice@example.com');
Lors de l'insertion d'une nouvelle personne dans la table "Personne", une nouvelle valeur de séquence est générée pour l'identifiant unique "id". Cette méthode assure que chaque personne a un identifiant distinct.
SERIAL/BIGSERIAL ; plus explicite et mieux contrôlable.
GENERATED ALWAYS AS IDENTITY : l’appli ne peut pas fournir de
valeur (sauf
OVERRIDING SYSTEM VALUE).
GENERATED BY DEFAULT AS IDENTITY : l’appli peut fournir une
valeur (sinon
génération automatique).-- Création (recommandé)
create table personne (
id bigint generated always as identity,
nom text not null,
age int not null
);
-- Insérer et récupérer l'identifiant créé (idiome PG)
insert into personne(nom, age)
values ('Alice', 30)
returning id;
-- Personnaliser l'IDENTITY (pas, départ, cycle…)
alter table personne
alter column id
add generated by default as identity
(start with 100, increment by 10, minvalue 100, cache 20);
nextval consommé n’est pas annulé par
ROLLBACK).
INSERT … RETURNING pour récupérer l’id dans une appli.-- Bon pattern : IDENTITY + contrainte de clé primaire
create table personne (
id bigint generated always as identity primary key,
nom text not null,
age int not null
);
-- Alternative si vous séparez :
create table personne (
id bigint generated by default as identity,
nom text not null,
age int not null,
constraint personne_pk primary key (id)
);
DROP /
OWNED BY).
nextval() côté application.EXCLUDE permettent d'empêcher les chevauchements ou
conflits complexes entre enregistrements.UNIQUE, elles utilisent des opérateurs de
comparaison personnalisés (=, &&, overlaps, etc.).btree_gist pour fonctionner avec des types comme les dates.CREATE EXTENSION IF NOT EXISTS btree_gist;
-- Empêcher les chevauchements de séjours pour un même client
ALTER TABLE sejour ADD CONSTRAINT sejour_no_overlap_per_client
EXCLUDE USING gist (
idc WITH =, -- même client
daterange(debut, fin, '[]') WITH && -- périodes qui se chevauchent
);
Cette contrainte empêche un client d'avoir deux séjours dont les dates se chevauchent, mais autorise des clients différents à avoir des séjours aux mêmes dates.
DEFERRABLE permettent de reporter la vérification à
la fin de la transaction.INITIALLY IMMEDIATE (par défaut) ou INITIALLY DEFERRED.-- Création d'une contrainte deferrable
ALTER TABLE sejour ADD CONSTRAINT sejour_no_overlap_per_client
EXCLUDE USING gist (idc WITH =, periode WITH &&)
DEFERRABLE INITIALLY IMMEDIATE;
-- Utilisation dans une transaction
BEGIN;
SET CONSTRAINTS sejour_no_overlap_per_client DEFERRED;
-- Mises à jour qui violent temporairement la contrainte
UPDATE sejour SET debut = '2025-01-15' WHERE ids = 1;
UPDATE sejour SET debut = '2025-01-10' WHERE ids = 2;
COMMIT; -- Vérification des contraintes ici
Les contraintes différées sont essentielles pour les opérations de maintenance ou les "swaps" de données qui nécessitent plusieurs étapes.
NOT VALID (pas de vérification des données
existantes).VALIDATE CONSTRAINT.-- Étape 1 : Ajout sans validation (rapide, pas de lock)
ALTER TABLE client
ADD CONSTRAINT chk_age_valid
CHECK (age BETWEEN 0 AND 120) NOT VALID;
-- Étape 2 : Diagnostic et correction
SELECT * FROM client WHERE age < 0 OR age > 120;
UPDATE client SET age = 0 WHERE age < 0;
-- Étape 3 : Validation (vérifie toutes les données)
ALTER TABLE client VALIDATE CONSTRAINT chk_age_valid;
Cette approche permet d'éviter les locks prolongés sur les grandes tables en production. Les nouvelles données respectent immédiatement la contrainte.
DOMAIN : Type personnalisé avec contraintes intégrées pour la réutilisabilité.ENUM : Type énuméré pour limiter les valeurs possibles.-- Domaine avec contrainte réutilisable
CREATE DOMAIN euro AS NUMERIC(10,2)
CHECK (VALUE >= 0);
-- Type énuméré
CREATE TYPE activite_t AS ENUM (
'surf', 'voile', 'kitesurf', 'plongée', 'rando', 'yoga'
);
-- Colonnes générées
ALTER TABLE sejour
ADD COLUMN periode daterange
GENERATED ALWAYS AS (daterange(debut, fin, '[]')) STORED,
ADD COLUMN nb_nuits int
GENERATED ALWAYS AS (fin - debut) STORED;
-- Utilisation
ALTER TABLE village ALTER COLUMN prix TYPE euro;
ALTER TABLE village ALTER COLUMN activite TYPE activite_t;
Avantages :
DOMAIN : Contraintes centralisées et réutilisablesENUM : Performance et sécurité des valeursGENERATED : Cohérence automatique des calculs-- Ajout d'une colonne de statut
ALTER TABLE sejour ADD COLUMN annule BOOLEAN NOT NULL DEFAULT FALSE;
-- Index partiel : unicité conditionnelle
CREATE UNIQUE INDEX uniq_client_debut_non_annule
ON sejour(idc, debut)
WHERE annule = FALSE;
-- Test : deux séjours à la même date
INSERT INTO sejour (idc, idv, debut, fin, annule)
VALUES (1, 1, '2025-01-01', '2025-01-05', TRUE); -- OK (annulé)
INSERT INTO sejour (idc, idv, debut, fin, annule)
VALUES (1, 1, '2025-01-01', '2025-01-05', FALSE); -- OK (différent statut)
INSERT INTO sejour (idc, idv, debut, fin, annule)
VALUES (1, 1, '2025-01-01', '2025-01-05', FALSE); -- ERREUR (doublon actif)
Cet index permet d'avoir plusieurs séjours annulés à la même date, mais un seul séjour actif par client et par date de début.
COMMENT pour faciliter la maintenance.-- Renommage des contraintes avec convention
ALTER TABLE client RENAME CONSTRAINT client_pkey
TO pk_client_idc;
-- Ajout avec nommage explicite
ALTER TABLE client ADD CONSTRAINT ck_client_age_valid
CHECK (age BETWEEN 0 AND 120);
-- Documentation
COMMENT ON CONSTRAINT ck_client_age_valid ON client
IS 'Âge doit être compris entre 0 et 120 ans';
COMMENT ON CONSTRAINT fk_sejour_client ON sejour
IS 'Référence vers la table client avec suppression en cascade';
-- Vérification des contraintes
SELECT
conname AS nom_contrainte,
contype AS type_contrainte,
obj_description(oid) AS description
FROM pg_constraint
WHERE conrelid = 'client'::regclass;
Convention recommandée :
pk_ : Primary Keyfk_ : Foreign Keyck_ : Checkuq_ : Uniqueex_ : ExcludeFormat : type_table_colonne(s)