Vues SQL expliquées : Créez, utilisez et évitez les pièges, avec des exemples
Une vue est une requête enregistrée que vous pouvez utiliser comme une table. Découvrez comment en créer un, pourquoi les vues assurent la cohérence des rapports, ce qu’elles font et ne font pas en termes de performances et les pièges qui les déjouent.
- Une vue est une requête nommée et stockée parmi laquelle vous pouvez sélectionner comme une table.
- Une vue normale ne stocke aucune donnée, elle affiche donc toujours les résultats actuels.
- Les vues simplifient les requêtes complexes, maintiennent la cohérence de la logique métier et peuvent restreindre l’accès aux colonnes.
- Ils ne réalisent pas eux-mêmes une requête plus rapidement, bien que les vues matérialisées le puissent.
La même requête de rapport de vingt lignes a été copiée dans cinq tableaux de bord, et chaque copie a légèrement dérivé. L’un compte les commandes annulées, l’autre non. Les vues SQL résolvent ce problème en définissant cette logique une fois, dans la base de données, sous un nom clair.
Nous avons exécuté tous les exemples ci-dessous dans SQLite 3.50, et les résultats affichés proviennent de cette exécution. Les vues sont en SQL standard, mais des détails tels que la mise à jour via une vue, les vues matérialisées et la gestion des dépendances varient selon les bases de données, et nous les soulignons.
Qu’est-ce qu’une vue ?
Une vue est une instruction SELECT enregistrée dans la base de données avec un nom. Lorsque vous interrogez la vue, la base de données exécute cette requête enregistrée. Il agit comme un tableau de lecture, mais une vue normale ne contient pas sa propre copie des données.
Pensez à un filtre enregistré dans une feuille de calcul. Le filtre n’est pas une seconde copie de la feuille. C’est une façon de regarder les mêmes données, qui reflètent toujours les valeurs les plus récentes.
Les exemples de tableaux
CREATE TABLE customers (
id INT PRIMARY KEY, name TEXT, city TEXT, email TEXT, credit_limit INT
);
CREATE TABLE orders (
id INT PRIMARY KEY, customer_id INT, total INT, status TEXT
);
INSERT INTO customers VALUES
(1,'Asha','Pune','asha@example.com',50000),
(2,'Ben','Delhi','ben@example.com',20000),
(3,'Chitra','Pune','chitra@example.com',80000);
INSERT INTO orders VALUES
(101,1,1200,'paid'), (102,1,800,'paid'),
(103,2,300,'pending'), (104,3,2500,'paid');
Créer une vue
Cette vue résume les commandes de chaque client. Il cache une jointure, un regroupement et une expression CASE derrière un nom simple :
CREATE VIEW customer_sales AS
SELECT c.id, c.name, c.city,
COUNT(o.id) AS orders,
COALESCE(SUM(CASE WHEN o.status = 'paid' THEN o.total END), 0) AS paid_total
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name, c.city;
Désormais, tout le monde peut l’utiliser, sans savoir comment il fonctionne :
SELECT * FROM customer_sales ORDER BY paid_total DESC;
-- 3 | Chitra | Pune | 1 | 2500
-- 1 | Asha | Pune | 2 | 2000
-- 2 | Ben | Delhi | 1 | 0
SELECT name, paid_total FROM customer_sales WHERE city = 'Pune';
-- Asha | 2000
-- Chitra | 2500
Ben apparaît avec zéro, car la vue utilise un LEFT JOIN et un COALESCE. Des décisions comme celle-ci, prises une fois vues, sont exactement ce qui assure la cohérence des rapports. Pour actualiser votre compréhension de la gestion NULL, consultez Valeurs SQL NULL.
Les vues sont toujours actuelles
Puisqu’une vue normale exécute sa requête à chaque fois, les nouvelles données apparaissent immédiatement. Nous avons ajouté une commande payante pour Ben et interrogé à nouveau la vue :
INSERT INTO orders VALUES (105, 2, 900, 'paid');
SELECT name, paid_total FROM customer_sales WHERE name = 'Ben';
-- Ben | 900
Il n’y avait aucune étape d’actualisation ni aucune copie à synchroniser. C’est la principale différence par rapport à l’enregistrement des résultats de la requête dans une table distincte.
Masquer les colonnes
Les vues sont souvent utilisées pour exposer uniquement les colonnes dont une personne ou une application a besoin. Ici, les adresses e-mail et les limites de crédit sont omises :
CREATE VIEW public_customers AS
SELECT id, name, city FROM customers;
-- columns: id, name, city
Dans les bases de données disposant d’autorisations, telles que PostgreSQL, SQL Server et MySQL, vous pouvez accorder à un utilisateur de reporting l’accès à la vue mais pas à la table sous-jacente. SQLite n’a pas de compte d’utilisateur, nous ne pouvons donc afficher que la restriction de colonne elle-même. Traitez une vue comme une couche de protection. Les données sensibles nécessitent toujours un contrôle d’accès approprié, et certaines bases de données offrent une sécurité au niveau des lignes pour filtrer les lignes par utilisateur.
Performance : les vues ne sont pas un gain de vitesse
Un mythe courant veut que les vues accélèrent les requêtes. Une vue normale est remplacée par sa définition lorsque vous l’interrogez, la base de données fait donc le même travail que si vous aviez écrit vous-même la requête complète. Notre plan d’exécution montrait que la jointure et le regroupement de la vue étaient exécutés dans le cadre de la requête :
EXPLAIN QUERY PLAN SELECT * FROM customer_sales WHERE city = 'Pune';
-- CO-ROUTINE customer_sales
-- SCAN c ...
-- SEARCH o USING AUTOMATIC COVERING INDEX (customer_id=?) LEFT-JOIN
-- USE TEMP B-TREE FOR GROUP BY
-- SCAN customer_sales
Ainsi, une vue sur une requête lente reste une requête lente. La vitesse vient des index et d’une bonne conception des requêtes, comme indiqué dans Optimisation des requêtes SQL et Explication des index SQL. Méfiez-vous également des vues construites sur d’autres vues. Les couches d’imbrication permettent de rejoindre facilement la même grande table plusieurs fois sans s’en apercevoir.
Vues matérialisées
Une vue matérialisée stocke ses résultats, comme une table mise en cache. Les lectures sont rapides, mais les données sont aussi récentes que la dernière actualisation.
-- PostgreSQL
CREATE MATERIALIZED VIEW daily_sales AS
SELECT order_date, SUM(total) AS revenue FROM orders GROUP BY order_date;
REFRESH MATERIALIZED VIEW daily_sales;
| Caractéristique | Vue normale | Vue matérialisée |
|---|---|---|
| Stocke les données | Non | Oui |
| Fraîcheur | Toujours à jour | Depuis la dernière actualisation |
| Vitesse de lecture | Identique à la requête | Rapide |
| Coût de stockage | Aucun | Oui |
| Bon pour | Simplification, cohérence | Rapports et tableaux de bord lourds |
Le soutien varie. PostgreSQL et Oracle disposent de vues matérialisées et SQL Server propose des vues indexées avec leurs propres règles. SQLite et MySQL n’en disposent pas, les utilisateurs utilisent donc un tableau récapitulatif régulier actualisé selon un calendrier. Nous n’avons pas exécuté l’exemple PostgreSQL pour cet article.
Conseil : Avant de créer une vue matérialisée, décidez dans quelle mesure les données peuvent être obsolètes. « Actualisé toutes les heures » doit être acceptable pour les personnes qui lisent le rapport, alors dites-le-leur.
Pouvez-vous mettre à jour une vue ?
Cela dépend de la base de données et de la vue. Une simple vue sur une seule table, sans regroupement ni DISTINCT, peut souvent être mise à jour dans PostgreSQL, MySQL et SQL Server, et la modification est transmise à la table. Une vue avec des jointures ou des agrégats ne le peut généralement pas, car la base de données ne peut pas déterminer quelle ligne modifier.
SQLite n’autorise pas du tout les écritures directes dans les vues. Notre tentative a échoué :
INSERT INTO customer_sales (name) VALUES ('X');
-- cannot modify customer_sales because it is a view
Certaines bases de données prennent en charge les déclencheurs INSTEAD OF pour rendre une vue accessible en écriture, et beaucoup proposent WITH CHECK OPTION, qui arrête les écritures qui ne seraient pas visibles via la vue. En pratique, la plupart des équipes conservent les vues en lecture seule et écrivent dans les tables.
Dépendances et casse
Une vue dépend des tables à partir desquelles elle lit. Nous avons créé une vue sur une table, puis supprimé la table :
CREATE TABLE ghost AS SELECT 1 AS x;
CREATE VIEW v_ghost AS SELECT x FROM ghost;
DROP TABLE ghost;
SELECT * FROM v_ghost;
-- no such table: main.ghost
SQLite a autorisé la suppression et n’a échoué que plus tard, lorsque la vue a été utilisée. D’autres bases de données, telles que PostgreSQL, refusent de supprimer une table dont dépend une vue, à moins que vous n’ajoutiez CASCADE, qui supprime également la vue. Quoi qu’il en soit, renommer ou supprimer une colonne peut interrompre les vues, alors vérifiez-les dans vos tests de régression après les modifications du schéma.
Il existe également un piège subtil avec SELECT * dans une vue. Nous avons créé CREATE VIEW star AS SELECT * FROM customers, puis ajouté une colonne au tableau. Dans SQLite, la vue récupère la nouvelle colonne. D’autres bases de données, notamment PostgreSQL, développent la liste des colonnes lors de la création de la vue, de sorte que les nouvelles colonnes n’apparaissent pas. Alors listez explicitement les colonnes. Il documente la vue et se comporte de la même manière partout.
Gestion des vues
| Tâche | Syntaxe commune |
|---|---|
| Créer | CREATE VIEW nom AS SELECT ... |
| Remplacer | CREATE OR REPLACE VIEW (PostgreSQL, MySQL, Oracle) |
| Remplacer dans SQL Server | CRÉER OU MODIFIER UNE VUE |
| Supprimer | Nom de la VUE DROP |
| Retirer en toute sécurité | VUE DROP SI EXISTE nom |
La suppression d’une vue supprime uniquement la requête enregistrée. Dans notre test, la table customers contenait toujours les trois lignes après la suppression de public_customers. Conservez les définitions de vue dans le contrôle de version avec vos migrations, afin que les modifications soient examinées comme n’importe quel autre code.
Vue vs CTE vs table
| Options | Durée de vie | Stocke les données | Idéal pour |
|---|---|---|---|
| Voir | Jusqu’à ce qu’il soit abandonné | Non | Logique partagée utilisée par de nombreuses requêtes |
| CTE | Une déclaration | Non | Organiser une seule requête complexe |
| Vue matérialisée | Jusqu’à ce qu’il soit abandonné | Oui | Lectures rapides de résultats coûteux |
| Tableau | Jusqu’à ce qu’il soit abandonné | Oui | Les données réelles |
Erreurs courantes
- En attente d’une augmentation de vitesse. Une vue normale exécute sa requête à chaque fois.
- Utilisation de
SELECT *dans les vues. Le comportement diffère entre les bases de données lorsque les tables changent. - Imbrication profonde. Les vues construites sur des vues masquent les jointures coûteuses.
- Utilisation de ORDER BY dans une vue. L’ordre n’est pas garanti lorsque vous l’interrogez, alors triez dans la requête externe.
- Noms peu clairs. Un préfixe tel que
v_, ou un nom clair commecustomer_sales, aide. - Oublier les vues lors des migrations. Testez-les après chaque changement de schéma.
Pour conclure
Les vues sont un moyen simple de donner une place à la logique importante dans la base de données. Utilisez-les pour maintenir la cohérence des rapports et masquer les colonnes inutiles, et non pour améliorer les performances. Pour commencer, recherchez une requête qui apparaît à plusieurs endroits de votre code, transformez-la en une vue avec des colonnes explicites et pointez vers elle chaque appelant.
Questions fréquentes
Qu’est-ce qu’une vue en SQL ?
Une vue est une requête SELECT enregistrée avec un nom. Vous l’interrogez comme une table et la base de données exécute la requête sous-jacente à chaque fois, de sorte que les résultats sont toujours à jour.
Une vue SQL stocke-t-elle des données ?
Une vue normale ne stocke pas les données, uniquement la requête. Une vue matérialisée stocke les résultats et doit être actualisée pour rester à jour.
Les vues sont-elles plus rapides que les tables ?
Non. Une vue normale fait le même travail que sa requête sous-jacente. Les vues matérialisées peuvent accélérer les lectures, au détriment du stockage et de la fraîcheur.
Pouvez-vous insérer dans une vue ?
Parfois. Les vues simples à table unique peuvent souvent être mises à jour dans PostgreSQL, MySQL et SQL Server. Les vues avec jointures ou regroupements ne le sont généralement pas, et SQLite ne le permet pas.
Qu’arrive-t-il à une vue si la table est supprimée ?
Cela dépend de la base de données. Certains refusent de supprimer la table alors qu’une vue en dépend, tandis que d’autres l’autorisent et la vue échoue lorsqu’elle est interrogée.
Continuez à apprendre
Besoin d’aide pour les tests, WordPress ou le référencement ?
Nous aidons les équipes à proposer de meilleurs logiciels et à développer leurs sites. Dites-nous sur quoi vous travaillez et nous vous proposerons une prochaine étape claire.
Plus de guides sur tests, IA et développement moderne
Vous avez apprécié cet article ? Choisissez un sujet et accédez directement à nos nouveaux didacticiels.
Les hallucinations de l'IA expliquées : pourquoi les modèles de langage inventent les choses et comment les réduire
Les hallucinations de l'IA ont expliqué : ce qu'elles sont, pourquoi les modèles de langage les produisent, les types courants, comment les réduire …
Lire l'article →DevOpsVariables d'environnement expliquées : fichiers .env, secrets et configuration correctement effectués
Variables d'environnement expliquées avec des exemples Python que nous avons exécutés : lecture et définition, pourquoi chaque valeur est une chaîne…
Lire l'article →Développement logicielLimitation du débit de l'API expliquée : algorithmes, en-têtes et gestion des erreurs 429
Limitation du débit de l'API expliquée avec une simulation que nous avons exécutée : compartiment de jetons, fenêtre fixe, fenêtre glissante, 429 ré…
Lire l'article →Automatisation des testsSe moquer en Python : unittest.mock, patch et les erreurs qui font mentir les tests
Moquerie en Python avec unittest.mock, testée : Mock et return_value, side_effect, correctifs où un nom est utilisé, spec et autospec, dates moqueus…
Lire l'article →Tests logicielsCouverture du code expliquée : couverture des lignes par rapport aux branches et ce que signifie réellement 100 %
Couverture du code expliquée avec une véritable exécution de cover.py : couverture des lignes, des branches et des conditions, lecture d'un rapport,…
Lire l'article →Bases de données et SQLDELETE vs TRUNCATE vs DROP dans SQL : différences, restauration et quand les utiliser
DELETE vs TRUNCATE vs DROP expliqué avec SQL testé : ce que chacun supprime, restauration, déclencheurs, réinitialisation d'identité, vitesse et en …
Lire l'article →Bases de données et SQLVues SQL expliquées : créez, utilisez et évitez les pièges, avec des exemples
Vues SQL expliquées avec les requêtes que nous avons exécutées : création d'une vue, résultats en direct, masquage des colonnes, performances, vues …
Lire l'article →Développement logicielInterface TypeScript vs Type : différences réelles, testées avec le compilateur
Interface TypeScript vs type, vérifiée avec le vrai compilateur : ce que les deux peuvent faire, ce qu'un seul peut faire, la fusion des déclaration…
Lire l'article →Développement logicielPython *args et **kwargs expliqués : fonctions flexibles avec des exemples clairs
Python *args et **kwargs expliqués avec le code que nous avons exécuté : emballage et déballage, ordre des paramètres, arguments de mot-clé uniqueme…
Lire l'article →Développement logicielFonctions Python Lambda : syntaxe, utilisations réelles et quand ne pas les utiliser
Fonctions Python lambda expliquées avec le code que nous avons exécuté : syntaxe, tri avec clé, carte et filtre, fermetures, piège de liaison tardiv…
Lire l'article →Intelligence artificielleQue sont les agents IA ? Comment ils fonctionnent, avec une simple boucle d'agent que vous pouvez exécuter
Que sont les agents IA ? Un guide simple sur la boucle d'agent, les outils, la mémoire et les garde-fous, avec une petite boucle Python que nous avo…
Lire l'article →DevOpsSurveillance vs observabilité : la vraie différence, avec les journaux, les métriques et les traces
Surveillance et observabilité expliquées : échecs connus et inconnus, journaux, métriques et traces, présentation pas à pas des incidents de paiemen…
Lire l'article →DevOpsVolumes Docker vs montages Bind : conserver les données du conteneur de la bonne manière
Volumes Docker et montages de liaison expliqués : pourquoi les données du conteneur disparaissent, volumes nommés, montages de liaison, tmpfs, exemp…
Lire l'article →Automatisation des testsTDD vs BDD : principales différences, une fonctionnalité conçue dans les deux sens et quand les utiliser
TDD vs BDD expliqué avec une fonctionnalité de remise construite dans les deux sens : refactor rouge-vert avec le code que nous avons exécuté, scéna…
Lire l'article →Développement logicielGit merge vs rebase : différences, exemples et quand utiliser chacun
Git merge vs rebase expliqué avec de vraies sorties de log, un tableau comparatif, la règle d'or du rebase et un flux de travail sûr pour les équipes.
Lire l'article →Développement logicielList comprehension Python : syntaxe, exemples et cas à éviter
La list comprehension Python expliquée : syntaxe, filtres, if-else, boucles imbriquées, temps mesurés et cas où une boucle for classique est préféra…
Lire l'article →Bases de données et SQLJointures SQL expliquées avec exemples (Inner, Left, Right, Full)
Comprenez les jointures SQL pas à pas avec des tables et requêtes d'exemple : INNER, LEFT, RIGHT, FULL, CROSS et SELF, plus erreurs courantes et con…
Lire l'article →