Tableaux ou tables normalisées
Déterminez quand les tableaux sont le bon choix.
Tableaux ou tables normalisées est une leçon SQL Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage SQL Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours SQL Academy comprend 4 leçons au total.
Deux façons de stocker plusieurs valeurs
Lorsqu'une seule ligne doit contenir plusieurs valeurs associées, PostgreSQL vous propose deux approches principales : les stocker dans une colonne de tableau de la même ligne, ou créer une table enfant où chaque valeur occupe sa propre ligne.
Savoir quand utiliser chacune de ces approches est une compétence essentielle pour concevoir des bases de données efficaces et faciles à maintenir.
Approche normalisée
Dans un schema entièrement normalisé, chaque donnée réside dans sa propre ligne. Si un utilisateur peut avoir plusieurs numéros de téléphone, vous créez une table user_phones avec une clé étrangère qui pointe vers users.
C'est le modèle relationnel classique et le choix par défaut dans la plupart des situations.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE user_phones (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users(id),
phone TEXT NOT NULL
);
INSERT INTO users (name) VALUES ('Alice'), ('Bob');
INSERT INTO user_phones (user_id, phone) VALUES
(1, '+1-555-0101'),
(1, '+1-555-0102'),
(2, '+1-555-0200');Approche par tableau
Le TEXT[] de PostgreSQL (ou tout autre type suivi de []) vous permet de stocker plusieurs valeurs directement dans une seule colonne. Aucune table supplémentaire n'est nécessaire.
Les mêmes données de numéros de téléphone peuvent être stockées dans une ligne compacte par utilisateur.
CREATE TABLE users_with_phones (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
phones TEXT[]
);
INSERT INTO users_with_phones (name, phones) VALUES
('Alice', ARRAY['+1-555-0101', '+1-555-0102']),
('Bob', ARRAY['+1-555-0200']);Interroger les tableaux est simple
La recherche au sein d'une colonne de tableau est simple avec l'opérateur ANY ou l'opérateur @> (contient). Vous pouvez trouver tous les utilisateurs qui possèdent un numéro de téléphone précis avec une simple clause WHERE.
-- Find users who have a specific phone number
SELECT name
FROM users_with_phones
WHERE '+1-555-0101' = ANY(phones);
-- Or using the array-contains operator
SELECT name
FROM users_with_phones
WHERE phones @> ARRAY['+1-555-0101'];Quand les tableaux sont préférables : recherches simples
Les tableaux sont un excellent choix lorsque :
- La liste de valeurs est lue ensemble comme une unité (étiquettes, libellés, catégories)
- Vous n'avez jamais besoin de faire une jointure sur des éléments individuels
- La liste a une limite supérieure naturelle et est rarement mise à jour par parties
Un exemple classique consiste à stocker des étiquettes sur un article de blog. Vous récupérez toujours toutes les étiquettes en une fois et interrogez rarement les articles en fonction d'une seule étiquette dans une jointure complexe.
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
tags TEXT[]
);
INSERT INTO posts (title, tags) VALUES
('Intro to SQL', ARRAY['sql', 'beginner', 'database']),
('Advanced Indexes', ARRAY['sql', 'performance', 'indexes']),
('NoSQL Overview', ARRAY['nosql', 'beginner']);
-- Get all posts tagged 'beginner'
SELECT title FROM posts
WHERE 'beginner' = ANY(tags);Quand les tables normalisées sont préférables : relations
Les tables normalisées sont un meilleur choix lorsque :
- Les valeurs individuelles ont besoin de leurs propres attributs (par ex., un numéro de téléphone possède un type : domicile/travail)
- Vous devez faire une jointure sur des valeurs individuelles
- Les valeurs changent indépendamment et fréquemment
- Vous avez besoin de l'intégrité référentielle grâce à des clés étrangères
-- Phone numbers need a 'type' attribute — array can't do this cleanly
CREATE TABLE user_phones (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users(id),
phone TEXT NOT NULL,
type TEXT CHECK (type IN ('home', 'work', 'mobile'))
);
INSERT INTO user_phones (user_id, phone, type) VALUES
(1, '+1-555-0101', 'home'),
(1, '+1-555-0102', 'work');La différence d'indexation
Avec une table normalisée, vous pouvez ajouter un index en arbre B standard sur la clé étrangère ou la colonne de valeur. Avec les tableaux, vous avez besoin d'un index GIN (index inversé généralisé) pour permettre des recherches rapides au sein du tableau.
Les index GIN fonctionnent bien, mais ils sont plus volumineux et plus lents à mettre à jour que les index en arbre B.
-- Index for fast array element lookups
CREATE INDEX idx_posts_tags ON posts USING GIN (tags);
-- Now this query uses the index efficiently
EXPLAIN SELECT title FROM posts
WHERE tags @> ARRAY['sql'];Agréger sur plusieurs lignes : avantage aux tables normalisées
Lorsque vous devez compter, regrouper ou agréger des valeurs individuelles, les tables normalisées sont bien plus naturelles. Agréger au sein de tableaux nécessite unnest(), qui développe d'abord le tableau en lignes — ce qui recrée essentiellement la structure normalisée au moment de l'interrogation.
-- Count posts per tag (array approach — needs unnest)
SELECT tag, COUNT(*) AS post_count
FROM posts, unnest(tags) AS tag
GROUP BY tag
ORDER BY post_count DESC;
-- With a normalized post_tags table this would be simpler:
-- SELECT tag, COUNT(*) FROM post_tags GROUP BY tag;Modifier les éléments d'un tableau
Mettre à jour ou supprimer un seul élément dans un tableau nécessite une syntaxe peu pratique — vous devez remplacer l'ensemble du tableau ou utiliser array_remove(). Dans une table normalisée, il vous suffit d'utiliser DELETE ou UPDATE sur la ligne concernée.
-- Remove a single tag from an array column
UPDATE posts
SET tags = array_remove(tags, 'beginner')
WHERE id = 1;
-- Append a new tag
UPDATE posts
SET tags = array_append(tags, 'tutorial')
WHERE id = 1;
SELECT title, tags FROM posts WHERE id = 1;Garantir la validité des valeurs
Dans une table normalisée, vous pouvez utiliser une clé étrangère pour garantir que chaque valeur provient d'un ensemble connu. Les tableaux ne peuvent pas faire référence à une autre table : ils ne prennent pas en charge les clés étrangères.
Si vous avez besoin d'une intégrité référentielle garantie pour chaque élément, une table enfant est la seule possibilité.
-- Normalized: only valid category IDs allowed (FK enforced)
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name TEXT UNIQUE NOT NULL
);
CREATE TABLE post_categories (
post_id INT REFERENCES posts(id),
category_id INT REFERENCES categories(id),
PRIMARY KEY (post_id, category_id)
);
-- Array: no constraint possible — any text value is accepted
-- UPDATE posts SET tags = ARRAY['totally_invalid_tag'] WHERE id = 1;Guide pratique pour choisir
Utilisez un tableau lorsque les données constituent une liste simple et plate, toujours lue comme une unité, sans attribut supplémentaire par élément, et que l'intégrité référentielle n'est pas requise (par ex. étiquettes, libellés, mots-clés de recherche).
Utilisez une table enfant normalisée lorsque chaque élément possède ses propres attributs, que vous faites des jointures ou des agrégations sur des valeurs individuelles, que vous avez besoin de clés étrangères ou que les éléments individuels sont fréquemment mis à jour ou supprimés.
-- Summary example: tags as array (good fit)
SELECT title, tags
FROM posts
WHERE tags @> ARRAY['sql']
ORDER BY title;
-- Unnest when you need row-level processing
SELECT title, unnest(tags) AS tag
FROM posts
ORDER BY title, tag;Vérification rapide
Quel scénario convient le mieux au stockage des données sous forme de tableau PostgreSQL plutôt que dans une table enfant normalisée ?
Récapitulatif de la leçon
Dans cette leçon, vous avez découvert les principaux compromis entre les tableaux et les tables normalisées dans PostgreSQL.
- Les tableaux sont compacts et pratiques pour les listes simples lues comme une unité, telles que les étiquettes — mais ils ne prennent pas en charge les clés étrangères, rendent les mises à jour par élément peu pratiques et nécessitent des index GIN pour effectuer des recherches rapides.
- Les tables normalisées prennent en charge les attributs par élément, l'intégrité assurée par des clés étrangères, l'agrégation efficace et les mises à jour simples au niveau des lignes — au prix d'une jointure supplémentaire.
- Le bon choix dépend de la façon dont vous interrogez, mettez à jour et reliez les données, et pas uniquement de leur mode de stockage.
Apprends SQL avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 46
- Leçons
- 183
Questions Fréquemment Posées
La leçon « Tableaux ou tables normalisées » est-elle gratuite ?
Oui — le texte complet de « Tableaux ou tables normalisées » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours SQL Academy, passe à CoddyKit PRO. Le cours SQL Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Tableaux ou tables normalisées » ?
Déterminez quand les tableaux sont le bon choix. Tu pratiques SQL Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer SQL Academy ?
Aucune expérience préalable n'est requise. SQL Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Tableaux ou tables normalisées » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon SQL Academy ?
Oui. Chaque leçon SQL Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Principes des colonnes de tableaux
- Rechercher dans des tableaux
- UNNEST et agrégation
- Tableaux ou tables normalisées