mygems

Comparer deux fichiers CSV et trouver ce qui a changé

diff compare des lignes : un export retrié paraît entièrement réécrit. Comparez plutôt par clé : ce qui est nouveau, disparu ou modifié.

Par uos ·

diff old.csv new.csv répond à la mauvaise question. Il compare des lignes : un fichier trié autrement ressort donc comme « tout a changé », et une ligne dont un seul champ a été corrigé ressort comme une suppression suivie d'un ajout, et non comme une modification.

Ce qu'il vous faut, c'est une comparaison par clé : quelles lignes sont nouvelles, lesquelles ont disparu et, pour celles présentes dans les deux fichiers, quels champs diffèrent. Trois questions, qui demandent trois réponses différentes.

Commencer par la structure

Avant de comparer le contenu, vérifiez que les deux fichiers sont comparables :

head -n 1 old.csv new.csv
wc -l old.csv new.csv

Un en-tête modifié est la cause la plus fréquente de comparaisons absurdes. Si une colonne a été ajoutée, renommée ou déplacée entre les deux exports, toute comparaison champ par champ est sans valeur tant que vous n'en tenez pas compte. Le nombre de lignes est le deuxième indice : un écart de trois est une semaine normale, un écart de 40 000 signifie généralement qu'un export a été tronqué ou filtré.

La comparaison en trois questions, en SQL

Choisissez d'abord votre clé : la colonne qui identifie le même enregistrement dans les deux fichiers. id, order_id, email. S'il n'y en a pas, passez à la dernière section.

Lignes présentes uniquement dans le nouveau fichier :

duckdb -c "SELECT * FROM read_csv('new.csv') n WHERE n.id NOT IN (SELECT id FROM read_csv('old.csv'))"

Lignes présentes uniquement dans l'ancien fichier :

duckdb -c "SELECT * FROM read_csv('old.csv') o WHERE o.id NOT IN (SELECT id FROM read_csv('new.csv'))"

Lignes présentes dans les deux, avec un champ modifié :

duckdb -c "SELECT o.id, o.status old_status, n.status new_status FROM read_csv('old.csv') o JOIN read_csv('new.csv') n USING (id) WHERE o.status IS DISTINCT FROM n.status"

IS DISTINCT FROM plutôt que <> est le détail qui compte : <> renvoie NULL dès que l'un des deux côtés est NULL, si bien qu'un champ passé de vide à rempli, ou de rempli à vide, disparaît silencieusement de vos résultats. C'est justement le changement que vous cherchiez le plus probablement.

Pour repérer les changements sur toutes les colonnes d'un coup, sans les nommer :

duckdb -c "SELECT * FROM read_csv('old.csv') EXCEPT SELECT * FROM read_csv('new.csv')"

EXCEPT compare des lignes entières et ignore l'ordre, ce qui en fait un bien meilleur diff que diff. Il vous dit *qu'*une ligne a changé, pas quel champ : associez-le donc à la jointure ci-dessus dès que vous savez quelles lignes regarder.

Quand les fichiers sont simplement triés autrement

Si vous voulez seulement savoir si le contenu est le même, triez et calculez une empreinte :

tail -n +2 old.csv | sort | md5sum
tail -n +2 new.csv | sort | md5sum

Même empreinte, même contenu, quel que soit l'ordre des lignes. Une empreinte différente ne dit rien sur ce qui a changé, mais cela prend une seconde et règle la question « est-ce le même export ? », qui s'avère souvent être toute l'enquête.

Pour un diff par ligne qui résiste au réordonnancement :

diff <(sort old.csv) <(sort new.csv)

C'est toujours basé sur les lignes : un changement d'un seul champ apparaît donc encore comme une paire, mais au moins le tri ne domine plus la sortie.

Outils dédiés

csvdiff et daff comparent tous deux par clé et produisent une sortie du type « la colonne status est passée de A à B pour la ligne 41 » plutôt que de vous montrer deux lignes. Si vous le faites régulièrement, installez l'un des deux. daff diff old.csv new.csv --output diff.html produit un tableau coloré lisible d'un coup d'œil, ce que rien de ce qui précède ne permet.

Git, si les fichiers sont versionnés. Définir un pilote de diff CSV dans .gitattributes fait passer git diff sur un fichier de données d'inutile à utile, et il suffit de deux lignes.

Excel, honnêtement, est mauvais pour cela. L'approche habituelle, une RECHERCHEV (VLOOKUP) par colonne vers l'autre feuille, fonctionne pour les petits fichiers, devient quadratique sur les gros et produit une grille de #N/A difficile à lire. La fusion de Power Query est bien meilleure, et presque personne ne s'en sert.

Lire les différences sur un téléphone

La version courante dans la vraie vie : deux exports à une semaine d'écart, dans votre messagerie, et la question est « qu'est-ce qui a changé ? » plutôt que « produire un rapport de rapprochement ».

La solution pratique n'est pas un diff du tout. Ajoutez une colonne indiquant la source, empilez les deux fichiers, triez par la clé et lisez les paires. Les champs modifiés sont visibles côte à côte, car les deux versions de chaque enregistrement sont désormais adjacentes. Pour quelques dizaines de lignes, c'est plus rapide que n'importe quel outil.

CSV File Viewer - Smart CSViPhone et iPad · Android

Le SQL directement sur le fichier suffit pour toute la comparaison : une jointure sur la clé avec IS DISTINCT FROM trouve les champs modifiés, et l'assistant IA prend en charge la version de la question que vous préférez poser avec des mots plutôt que d'écrire.

Ce que ça fait

Nombres, dates et fausses différences

Une comparaison fait souvent ressortir un grand nombre de « changements » qui n'en sont pas. Écartez-les avant d'enquêter :

  • Espaces en fin de valeur. "active" et "active " diffèrent. Comparez des valeurs passées par trim(), sauf si les espaces ont un sens, ce qui n'arrive presque jamais.
  • Format des nombres. 1000, 1,000 et 1000.00 sont un seul nombre et trois chaînes. Convertissez les deux côtés en type numérique avant de comparer.
  • Formats de date. 01/02/2026 contre 2026-02-01 et, pire, 01/02/2026 qui signifie février dans un fichier et janvier dans l'autre. Convertissez les deux en dates plutôt que de comparer du texte.
  • Bruit des flottants. 0.1 + 0.2 ne vaut 0.3 dans aucun des langages que vous utilisez. Arrondissez à la précision qui compte avant de comparer des décimaux.
  • Encodage. Un nom qui s'affiche José dans un fichier et José dans l'autre est une différence d'encodage, pas un changement de données.

Chacun de ces points produit des milliers de différences sur un gros fichier, et c'est ainsi qu'une comparaison finit par « tout afficher comme modifié ».

CSV Editor - Smart CSViPhone et iPad

Quand la comparaison débouche sur une correction, comme normaliser une colonne, arrondir un décimal ou corriger les lignes qui ont vraiment changé, une colonne de formule l'applique à chaque ligne, et le résultat est enregistré dans le CSV.

Ce que ça fait

Quand il n'y a pas de clé

Parfois les fichiers n'ont aucun identifiant : deux exports d'un journal, deux listes de transactions. Vous avez deux options, et ce sont toutes deux des compromis.

Construire une clé composite à partir des colonnes qui identifient ensemble une ligne : date plus montant plus libellé, par exemple. Cela marche quand la combinaison est réellement unique, et échoue sans bruit quand elle ne l'est pas : deux transactions identiques le même jour n'en font plus qu'une, et la comparaison signale une suppression fantôme.

Comparer comme des multi-ensembles. Comptez les occurrences de chaque ligne distincte dans chaque fichier et comparez les comptes. C'est ce qu'il faut pour les journaux et les transactions, où la même ligne apparaît légitimement plusieurs fois et où le changement significatif est le nombre de fois :

duckdb -c "SELECT *, count(*) n FROM read_csv('old.csv') GROUP BY ALL"

Lancez-le sur les deux fichiers et comparez les colonnes n. C'est la seule approche qui donne un résultat juste sur des données riches en doublons.

Questions

Comment comparer deux fichiers CSV et trouver les différences ?
Comparez par clé plutôt que par ligne. Posez trois questions distinctes : quelles clés sont uniquement dans le nouveau fichier, lesquelles uniquement dans l'ancien, et, pour les clés présentes dans les deux, quels champs diffèrent. En SQL, cela donne deux anti-jointures et une jointure avec `IS DISTINCT FROM` par colonne. Un simple `diff` signale un changement d'un seul champ comme une suppression plus un ajout, et un fichier retrié comme entièrement modifié.
Pourquoi diff indique-t-il que chaque ligne a changé alors que les données semblent identiques ?
Presque toujours parce que les deux exports sont triés différemment. `diff` compare les lignes dans l'ordre, si bien qu'un fichier réordonné paraît entièrement réécrit. `diff <(sort old.csv) <(sort new.csv)` supprime cet effet, et `SELECT * FROM old EXCEPT SELECT * FROM new` ignore complètement l'ordre des lignes.
Comment comparer deux fichiers CSV dans Excel ?
Utilisez la fusion de Power Query plutôt que RECHERCHEV (VLOOKUP). Une RECHERCHEV par colonne vers l'autre feuille fonctionne pour quelques centaines de lignes, devient quadratique sur les gros fichiers et produit une grille de #N/A difficile à lire. Power Query joint sur une clé, garde les deux versions de chaque colonne côte à côte et s'actualise quand les fichiers sont remplacés.
Pourquoi ma comparaison de CSV affiche-t-elle des milliers de faux changements ?
À cause de différences de format qui ne sont pas des différences de données : espaces en fin de valeur, séparateurs de milliers, `1000` contre `1000.00`, deux formats de date, bruit des nombres flottants et encodages de texte incompatibles. Normalisez les deux côtés (supprimer les espaces, convertir les nombres en type numérique, interpréter les dates comme des dates, arrondir les décimaux) avant de comparer, sinon chacun de ces points apparaît comme un changement sur chaque ligne concernée.
Comment comparer des fichiers CSV sans colonne d'identifiant ?
Soit vous construisez une clé composite à partir des colonnes qui identifient ensemble une ligne, soit vous comparez les fichiers comme des multi-ensembles, en comptant les occurrences de chaque ligne distincte des deux côtés et en comparant les comptes. La seconde méthode est la bonne pour les journaux et les transactions, où la même ligne peut légitimement se répéter et où le changement qui compte est le nombre d'apparitions.
Quel est le moyen le plus rapide de savoir si deux fichiers CSV sont identiques ?
Retirez l'en-tête, triez et calculez l'empreinte : `tail -n +2 file.csv | sort | md5sum` sur chacun. Des empreintes identiques signifient un contenu identique, quel que soit l'ordre des lignes. Cela ne dit rien sur ce qui diffère, mais cela prend une seconde et règle souvent la question que vous vous posiez : les deux exports sont-ils le même ?

uos — Développe CSV Editor et Smart CSV Viewer, et a rapproché assez de paires d'exports pour se méfier de tout diff par ligne.