Comment valider des fichiers CSV, JSON et Excel
Un guide pratique de la validation des fichiers plats — pourquoi les tableurs cassent d'une manière que les bases de données ne connaissent pas, les six contrôles qui l'attrapent, et comment exécuter sur un CSV le même contrat de données que sur votre entrepôt.
· 11 min read
Pour valider un fichier CSV, JSON ou Excel, chargez-le dans quelque chose qui parle SQL, puis exécutez les mêmes contrôles que sur une table d'entrepôt : valeurs nulles dans les colonnes obligatoires, clés en double, valeurs hors de l'ensemble autorisé, nombres hors d'une plage plausible, chaînes malformées et lignes périmées. La différence tient à ce qui vient *avant* les contrôles. Une colonne de base de données a un type déclaré et refuse les insertions non conformes ; une colonne de tableur contient ce que la dernière personne y a tapé. La plupart des incidents sur fichiers plats sont des problèmes d'analyse syntaxique et de typage, pas des violations de règles — c'est donc au moment du parsing que la validation commence vraiment.
Pourquoi les fichiers plats cassent différemment
Une table d'entrepôt a déjà rejeté les pires données avant que vous ne les voyiez. Un fichier n'a rien rejeté du tout.
Il n'y a pas de schéma, seulement une supposition. Tout lecteur CSV déduit les types à partir des N premières lignes. Une colonne qui contient 1, 2, 3 sur dix mille lignes et N/A à la ligne dix mille et une est une colonne entière jusqu'à ce qu'elle cesse brusquement de l'être. Changez la taille de l'échantillon et le même fichier s'analyse différemment.
Excel réécrit vos données en silence. Les zéros initiaux disparaissent des codes postaux et des codes produits, les identifiants longs se transforment en notation scientifique (1.23457E+14), et tout ce qui ressemble à une date en devient une. Le problème est suffisamment connu pour que le comité de nomenclature des gènes humains ait renommé plusieurs gènes, Excel convertissant sans cesse des symboles comme SEPT2 en dates. Si un fichier est passé par Excel, partez du principe que certaines colonnes ont été reformatées en chemin.
Les délimiteurs et les guillemets relèvent eux aussi de la supposition. Un export délimité par des points-virgules, produit dans une locale européenne et analysé comme délimité par des virgules, donne une seule colonne géante. Un guillemet non échappé à l'intérieur d'un champ décale d'un cran toutes les colonnes suivantes — et seulement pour certaines lignes, ce qui est pire qu'un échec franc.
L'encodage n'est pas déclaré. Un fichier écrit en Windows-1252 et lu en UTF-8 transforme é en é. Rien ne lève d'erreur ; les données sont simplement fausses, discrètement.
L'en-tête n'est pas forcément la ligne 1. Les exports des outils de reporting commencent couramment par une ligne de titre, une ligne vide et une mention « Généré le… » avant le véritable en-tête.
Rien de tout cela n'est une violation de règle. Tous ces cas produisent un fichier qui s'analyse « avec succès » en données inexploitables, et c'est pourquoi un flux de travail sur fichiers plats a besoin d'une étape d'aperçu et de confirmation avant l'exécution de la moindre règle. Une fois l'analyse correcte, le travail devient identique à la validation d'une table d'entrepôt, que le guide complet de la validation des données traite en détail.
Commencez par réussir l'analyse du fichier
Avant d'écrire le moindre contrôle, confirmez quatre choses :
- Le délimiteur et le caractère de citation. La virgule, le point-virgule, la barre verticale et la tabulation sont tous courants. Regardez l'aperçu analysé, pas le texte brut.
- La ligne d'en-tête. La première colonne s'appelle-t-elle
order_id, ouExport des ventes — T3? - Les types déduits. C'est l'étape que l'on saute. Si une colonne d'identifiants est revenue en nombre, vous avez déjà perdu les zéros initiaux.
- Le nombre de lignes. Si un fichier de 50 000 lignes s'affiche en aperçu avec 3 lignes, la gestion des guillemets est cassée.
Catalyst en fait une étape explicite : vous importez le fichier, il l'analyse avec DuckDB et affiche les colonnes obtenues, les types déduits et un aperçu des lignes, et vous ajustez le délimiteur, le caractère de citation et le réglage d'en-tête jusqu'à ce que l'aperçu soit juste. Ce n'est qu'ensuite que le fichier devient un jeu de données. Pour les fichiers .xls et .xlsx, vous choisissez également la feuille de calcul, faute de quoi un classeur avec les onglets Data, Pivot et Notes retiendra par défaut celui qui se trouve en premier.
Une remarque spécifique aux identifiants : si une colonne est un code et non une quantité — numéros de commande, références SKU, codes postaux, numéros de compte —, vous la voulez en texte, pas en nombre. On n'y fait jamais d'arithmétique, et la typer en nombre est précisément ce qui transforme 00123 en 123 définitivement.
Les six contrôles dont tout fichier a besoin
Une fois que le fichier est un jeu de données, il est interrogeable en SQL ordinaire. Catalyst enregistre chaque fichier importé comme une vue DuckDB, si bien que le moteur de validation exécute le même SQL compilé que sur Postgres — pas de chemin de code séparé ni de second langage de règles.
1. Complétude — valeurs nulles dans les colonnes obligatoires
SELECT count(*) AS violations
FROM files.orders_csv
WHERE order_id IS NULL OR trim(order_id) = '';
Pour les fichiers, contrôlez toujours la chaîne vide en plus de NULL. Un CSV n'a pas de notion de valeur nulle — un champ vide n'est que deux virgules adjacentes, et les lecteurs divergent sur la question de savoir si cela devient NULL ou ''. La moitié de vos lignes peut être vide pendant qu'un contrôle naïf IS NULL annonce une complétude parfaite.
2. Unicité — clés en double
SELECT count(*) AS violations
FROM (
SELECT order_id
FROM files.orders_csv
WHERE order_id IS NOT NULL
GROUP BY order_id
HAVING count(*) > 1
);
Les fichiers n'ont ni clé primaire ni index unique : rien n'a jamais empêché un doublon. La cause la plus fréquente est banale : deux exports couvrant des plages de dates qui se recouvrent, concaténés.
3. Conformité — valeurs hors de l'ensemble autorisé
SELECT count(*) AS violations
FROM files.orders_csv
WHERE status IS NOT NULL
AND status NOT IN ('pending', 'paid', 'shipped', 'refunded');
Gardez la protection contre les valeurs nulles — NULL NOT IN (...) vaut NULL, donc ces lignes sortent silencieusement du compte.
Ce contrôle justifie son existence sur les fichiers plus qu'ailleurs, car les colonnes de tableur saisies librement dérivent : paid, Paid, PAID, paid avec une espace finale. Envisagez de supprimer les espaces et de passer en minuscules dans la règle si la source est maintenue à la main.
4. Exactitude — nombres hors d'une plage plausible
SELECT count(*) AS violations
FROM files.orders_csv
WHERE total_amount IS NOT NULL
AND (total_amount < 0 OR total_amount > 100000);
Attention aux symboles monétaires et aux séparateurs de milliers. €1.234,56 ne s'analyse pas comme un nombre dans la plupart des lecteurs ; soit cela échoue, soit cela devient 1.234. Si une colonne numérique est revenue en texte dans l'aperçu, c'est la raison.
5. Conformité — identifiants malformés
SELECT count(*) AS violations
FROM files.orders_csv
WHERE reference IS NOT NULL
AND NOT regexp_matches(reference, '^ORD-[0-9]{6}#39;);
DuckDB utilise RE2 : les motifs ancrés, les classes de caractères et les quantificateurs fonctionnent tels quels — sans traduction, contrairement à SQL Server. Un contrôle de motif est le moyen le plus rapide d'attraper une colonne reformatée par Excel : si ORD-000123 est devenu ORD-123, il se déclenche.
6. Ponctualité — fraîcheur
SELECT count(*) AS violations
FROM files.orders_csv
WHERE created_at < now() - INTERVAL 24 HOUR;
Les dates sont le type de colonne le plus dangereux d'un fichier plat. 03/04/2026 est le 3 avril ou le 4 mars selon la locale de celui qui l'a produit, et les deux s'analysent sans erreur. Si une colonne de dates compte, contrôlez sa plage explicitement — un fichier où toutes les dates tombent dans les douze premiers jours du mois est un fichier analysé avec le mauvais ordre jour/mois.
Recouper un fichier avec votre entrepôt
Le contrôle le plus utile sur un fichier plat ne porte souvent pas sur le fichier pris isolément. Une liste de fournisseurs, un tableau de corrections manuelles ou un export financier sont en général destinés à se réconcilier avec quelque chose que vous détenez déjà :
SELECT count(*) AS violations
FROM files.suppliers_xlsx f
LEFT JOIN files.known_suppliers k ON f.supplier_id = k.id
WHERE f.supplier_id IS NOT NULL
AND k.id IS NULL;
Les lignes du fichier qui n'existent pas en amont sont soit de nouveaux enregistrements, soit des fautes de frappe, et savoir de quoi il s'agit avant de les charger est tout l'intérêt de valider à l'entrée plutôt qu'après coup.
Des contrôles ponctuels au contrat de données
La raison de traiter un fichier comme un jeu de données plutôt que comme un script jetable, c'est que les fichiers reviennent. Le même tableau fournisseurs arrive chaque mois, de la même personne, avec les mêmes modes de défaillance. Consigner les attentes une fois signifie que le deuxième import est contrôlé sans effort supplémentaire.
Catalyst utilise l'Open Data Contract Standard, et un contrat de fichier ressemble exactement à un contrat d'entrepôt :
apiVersion: v3.0.0
kind: DataContract
info:
title: orders_csv
version: 1.0.0
owner: finance-ops
schema:
- name: orders_csv
physicalName: orders_csv
physicalType: table
properties:
- name: order_id
logicalType: string
required: true
primaryKey: true
quality:
- rule: nullCount
dimension: completeness
severity: error
mustBe: "0"
- rule: duplicateCount
dimension: uniqueness
severity: error
mustBe: "0"
- name: status
logicalType: string
quality:
- rule: validValues
dimension: conformity
severity: error
mustBe: "['pending', 'paid', 'shipped', 'refunded']"
- name: total_amount
logicalType: number
quality:
- rule: between
dimension: accuracy
severity: error
mustBe: "[0, 100000]"
- name: reference
logicalType: string
quality:
- rule: regex
dimension: conformity
severity: error
mustBe: "'^ORD-[0-9]{6}#39;"
quality:
- rule: rowCount
dimension: consistency
severity: error
mustBe: "> 0"
Deux points méritent d'être soulignés.
La règle regex sur reference est ici en gravité error, alors que les guides consacrés aux entrepôts la placent en warning. Cette inversion est délibérée : dans un entrepôt, le type de la colonne contraint déjà la valeur, si bien qu'un motif non respecté relève généralement d'une bizarrerie de saisie. Dans un fichier, un motif non respecté indique souvent que l'*analyse* a mal tourné — et cela mérite qu'on s'arrête.
La règle rowCount au niveau de la table compte davantage ici aussi. Un résultat vide après un import signifie généralement que le délimiteur ou la feuille sélectionnée n'était pas le bon, pas que l'entreprise n'a eu aucune commande.
Limites pratiques
Quelques points à connaître avant de brancher un flux de travail là-dessus :
- Les imports sont plafonnés à 25 Mo par fichier, vérifiés par rapport au
Content-Lengthdéclaré puis à nouveau pendant la lecture, un client pouvant mal déclarer sa taille. Les extractions plus volumineuses ont leur place dans un entrepôt. - Les formats pris en charge sont
.csv,.json(tableau d'objets ou NDJSON),.xlset.xlsx. Les tableurs sont normalisés en CSV une fois pour toutes à l'import, si bien que tout ce qui vient ensuite n'a affaire qu'à un seul chemin d'analyse. - Les fichiers sont des instantanés. Un jeu de données pointe vers les octets que vous avez importés ; réimporter est un acte explicite. C'est le bon comportement par défaut — vous voulez savoir quand les données sous-jacentes ont changé.
- Les fichiers importés sont chiffrés au repos et lus uniquement pour répondre à un contrôle.
Pièges des fichiers plats à connaître
| Piège | Ce qui se passe | Que faire |
|---|---|---|
Chaîne vide vs NULL | La complétude passe malgré des lignes vides | Contrôler IS NULL OR trim(col) = '' |
| Zéros initiaux supprimés | 00123 devient 123, les jointures échouent | Typer les colonnes d'identifiants en texte |
| Notation scientifique | Les identifiants longs deviennent 1.23457E+14 | Typer en texte ; ajouter une règle regex |
| Dates ambiguës | 03/04 s'analyse dans les deux sens | Contrôler la plage de la colonne de dates |
| Mauvais délimiteur | Tout atterrit dans une seule colonne | Confirmer l'aperçu avant d'enregistrer |
| Mauvais encodage | é devient é | Réexporter en UTF-8 |
| Type déduit d'un échantillon | Un N/A tardif casse une colonne numérique | Vérifier les types déduits dans l'aperçu |
| Lignes de titre au-dessus de l'en-tête | Les colonnes s'appellent Column1, Column2 | Définir explicitement la ligne d'en-tête |
| Mauvaise feuille de calcul | On valide l'onglet Notes | Choisir la feuille à l'import |
Questions fréquentes
Comment valider un fichier CSV sans écrire de code ?
Importez-le, confirmez l'analyse (délimiteur, caractère de citation, ligne d'en-tête, types déduits), puis déclarez les attentes — obligatoire, unique, valeurs autorisées, plage numérique, motif. Catalyst transforme le fichier en un jeu de données adossé à DuckDB et compile ces règles en SQL, si bien que le même format de contrat couvre un CSV et une table d'entrepôt.
Puis-je valider des fichiers Excel, ou dois-je d'abord les convertir en CSV ?
Les fichiers .xls et .xlsx s'importent directement ; vous choisissez la feuille de calcul au moment de l'import. Le fichier est normalisé en CSV une fois pendant l'ingestion, de sorte que tout ce qui suit dispose d'un chemin d'analyse unique. Sachez que tout ce qu'Excel a touché a pu être reformaté au passage — zéros initiaux supprimés, notation scientifique, dates corrigées automatiquement —, ce qui est exactement ce que les règles de motif et de plage sont là pour attraper.
Pourquoi la validation de mon CSV passe-t-elle alors que les données sont manifestement fausses ?
Presque toujours parce que c'est l'analyse qui est fausse, pas les règles. Les causes habituelles : un champ vide est devenu '' au lieu de NULL, si bien que le contrôle de complétude a vu une valeur ; le mauvais délimiteur a tout mis dans une seule colonne, si bien que la colonne contrôlée est vide et que toutes les protections contre les valeurs nulles l'ont ignorée ; ou encore une colonne déduite comme texte fait comparer des chaînes à une règle de plage numérique. Vérifiez l'aperçu analysé avant de faire confiance à une exécution en succès.
Quelle taille de fichier puis-je valider ?
Catalyst plafonne les imports à 25 Mo par fichier, ce qui couvre la plupart des exports manuels, des tableaux de référence et des listes de fournisseurs. Au-delà, le fichier a vraiment sa place dans un entrepôt — chargez-le dans PostgreSQL ou BigQuery et validez-le là, où l'élagage de partitions et les index rendent les contrôles peu coûteux.
Valider un fichier est-il différent de valider une table de base de données ?
Les règles sont identiques — le même contrat, les mêmes six contrôles. Ce qui diffère, c'est tout ce qui les précède. Une base de données a déjà imposé des types et rejeté les lignes malformées ; un fichier n'a rien imposé, de sorte que l'essentiel des défauts se loge dans l'analyse et le typage. Réussissez l'analyse et le reste est le même travail.