DataSuits

COUNT en SQL : compter sans oublier les valeurs manquantes

Blog
COUNT en SQL : compter sans oublier les valeurs manquantes
Emoji de visage masculin avec lunettes rondes, clin d'œil et langue tirée sur fond beige.
Emoji 3D d'un homme souriant avec une barbe noire et une coiffure en dreadlocks sur fond violet clair.
Emoji féminin avec peau brune, cheveux tressés noirs, boucles d’oreilles dorées, nez percé, clin d'œil et langue tirée.
Visage animé avec cheveux violets, sourire les yeux fermés et main montrant les doigts croisés.

Candidater à l’une de nos formations DataSuits

Remplissez ce court formulaire pour candidater à la formation de votre choix. Notre équipe pédagogique vous contactera rapidement pour échanger sur votre parcours et vous accompagner dans la suite de votre inscription.

Publié le Par
Dans ce carnet
Carnet pratique · SQL

COUNT(*) compte les lignes ; COUNT(colonne) compte les valeurs non nulles de cette colonne. Une demande dont le montant manque reste une demande. En SQL, le langage utilisé pour interroger les bases de données, ces deux comptages répondent donc à deux questions différentes.

Avant de partager une moyenne, affichez la base sur laquelle elle repose. Dans notre exercice fictif, vous avez six demandes, mais seulement quatre montants connus : la moyenne de ces montants vaut 55 €. La présenter comme la moyenne de toutes les demandes masquerait les deux informations manquantes.

Le réflexe que je vous recommande

Affichez ensemble le nombre de lignes, le nombre de valeurs connues et le nombre d’absences. Vous verrez alors ce que votre résultat décrit, et ce qu’il ne permet pas encore de dire.

Pourquoi COUNT SQL donne-t-il deux nombres sur le même fichier ?

Parce qu’une ligne peut exister sans que toutes ses colonnes soient renseignées. Voici six demandes inventées. Chaque identifiant id correspond à une demande différente ; un même client peut déposer plusieurs demandes légitimes.

Dans ce jeu, NULL dans montant signifie « montant inconnu ». Le zéro de la demande 2 est, lui, une valeur connue. Le NULL de client indique un identifiant client manquant. Aucune de ces absences ne doit entraîner la disparition de la demande.

Six demandes fictives — montants en euros
idclientmontant
1C1100
2C10
3C2NULL
4NULL80
5C340
6C3NULL

Vous pouvez contrôler le fichier sans écrire de requête : six lignes ; quatre nombres dans montant, dont zéro ; deux montants inconnus. Les montants connus donnent 100 + 0 + 80 + 40 = 220 €. Cette somme ne démontre pas le montant total des six demandes.

Comment reproduire l’exercice dans une base de test ?

Créez une base vide et exécutez le script ci-dessous une seule fois. Il crée une table nommée demandes_demo et insère les six demandes. Utilisez une base de test séparée, afin de conserver vos données de travail intactes.

CREATE TABLE demandes_demo (
  id INTEGER PRIMARY KEY,
  client TEXT,
  montant NUMERIC
);
INSERT INTO demandes_demo (id, client, montant) VALUES
  (1, 'C1', 100),
  (2, 'C1', 0),
  (3, 'C2', NULL),
  (4, NULL, 80),
  (5, 'C3', 40),
  (6, 'C3', NULL);

Écrivez NULL sans guillemets. 'NULL' serait un texte, pas la marque d’absence voulue. La clé primaire rend id unique et non nul dans ce jeu : compter id revient ici à compter les demandes.

Les requêtes de ce carnet ont été exécutées avec SQLite, un moteur de base de données. Nous citons aussi PostgreSQL pour expliquer les règles, sans prétendre avoir effectué une seconde exécution sur ce moteur. Si vous débutez, notre cours SQL avec requêtes expliquées présente les premières commandes.

Comment compter les lignes, les montants et les valeurs manquantes ?

Calculez les trois nombres dans la même requête, sur le même périmètre. La différence entre les lignes et les montants non nuls donne ici le nombre de montants absents.

SELECT
  COUNT(*) AS demandes,
  COUNT(montant) AS montants_connus,
  COUNT(*) - COUNT(montant) AS montants_absents
FROM demandes_demo;
Résultat vérifié sur le jeu fictif
DemandesMontants connusMontants absents
642

La documentation PostgreSQL des fonctions d’agrégation distingue le comptage des lignes et celui des valeurs non nulles. Ces fonctions résument plusieurs lignes en un résultat. Les fonctions correspondantes de SQLite suivent cette distinction pour les requêtes utilisées ici.

Zéro compte. La demande 2 entre bien dans COUNT(montant), puisque son montant vaut 0 et non NULL. En revanche, les demandes 3 et 6 n’y entrent pas.

Si vous ajoutez un filtre, les trois comptages portent sur les lignes retenues par ce filtre. Après une jointure, ils portent sur son résultat, qui peut contenir davantage de lignes que votre table d’origine. Notre exercice LEFT JOIN et WHERE détaille un cas où COUNT(*) et le comptage d’un identifiant ne représentent plus la même chose.

Des fiches de données renseignées, une fiche marquée d’un cercle et des fiches sans information sont conservées dans le même ensemble.
Illustration originale et symbolique : une information manquante n’efface pas la ligne qui la porte. Les objets ne représentent pas exactement les données de l’exercice.

COUNT(client) compte-t-il le nombre de clients ?

Il compte les lignes dont client n’est pas NULL. Il ne retire pas les répétitions. Dans notre fichier, cinq demandes ont un identifiant client renseigné, mais seulement trois identifiants différents sont connus.

SELECT
  COUNT(client) AS demandes_client_renseigne,
  COUNT(DISTINCT client) AS identifiants_clients_distincts
FROM demandes_demo;

Résultat : 5 et 3. C1 apparaît deux fois, C2 une fois et C3 deux fois. DISTINCT demande de compter chaque valeur distincte une seule fois dans ce calcul ; il ne supprime aucune demande de la table.

La documentation PostgreSQL des expressions d’agrégation précise que COUNT(DISTINCT colonne) compte les valeurs distinctes non nulles. Le client manquant de la demande 4 n’ajoute pas un identifiant à ce résultat.

Écrivez donc « trois identifiants clients distincts connus ». Vous ne savez pas si la demande 4 appartient à C1, C2, C3 ou à quelqu’un d’autre. Le calcul ne suffit pas à déterminer le nombre total de clients représentés.

Pourquoi la moyenne vaut-elle 55 € plutôt que 36,67 € ?

AVG(montant) calcule ici la moyenne des quatre montants non nuls. Les deux valeurs inconnues sont exclues de cette moyenne, tandis que le zéro connu reste inclus. La base de calcul est donc quatre valeurs, pas six demandes.

SELECT
  COUNT(*) AS demandes,
  COUNT(montant) AS base_de_la_moyenne,
  SUM(montant) AS somme_des_montants_connus,
  AVG(montant) AS moyenne_des_montants_connus
FROM demandes_demo;

Le résultat donne 6, 4, 220 et 55. Le contrôle à la main est (100 + 0 + 80 + 40) / 4 = 55 €. Ce résultat décrit les montants disponibles ; il ne prouve pas que les demandes sans montant auraient la même moyenne.

Une phrase de rapport que l’on peut défendre

« Dans cet extrait fictif, 4 demandes sur 6 ont un montant renseigné. La somme des montants connus est de 220 € et leur moyenne est de 55 €. Deux montants restent inconnus. »

Vous pourriez obtenir environ 36,67 € avec AVG(COALESCE(montant, 0)). COALESCE prend la première valeur non nulle proposée ; la documentation PostgreSQL de COALESCE détaille ce remplacement.

Le calcul deviendrait (100 + 0 + 0 + 80 + 40 + 0) / 6. Vous auriez posé une nouvelle hypothèse : les deux montants inconnus valent zéro. Cette hypothèse n’est pas fournie par notre jeu. Je vous recommande de garder les absences visibles plutôt que de les convertir silencieusement en chiffres.

Exercice bonus : que change une nouvelle demande sans montant ?

Ajoutez une septième demande fictive, dont le montant est inconnu, puis rejouez les requêtes de comptage et de moyenne. Prédisez les comptages, la somme et la moyenne avant de lire la correction.

INSERT INTO demandes_demo (id, client, montant)
VALUES (7, 'C4', NULL);
Afficher la correction : ajout d’un NULL puis d’un zéro

Vous obtenez 7 demandes, 4 montants connus et 3 montants absents. La somme des montants connus reste 220 € ; leur moyenne reste 55 €. La population a changé, mais la base numérique de cette moyenne est restée la même.

Pour distinguer l’absence du zéro, modifiez ensuite uniquement cette ligne :

UPDATE demandes_demo
SET montant = 0
WHERE id = 7;

Vous avez maintenant 7 demandes, 5 montants connus et 2 montants absents. La somme reste 220 €, mais la moyenne devient 220 / 5 = 44 €. Le zéro ajoute une observation connue à la base de calcul.

Cette différence ne démontre aucune évolution d’une activité réelle : les données sont inventées pour vérifier ce que les fonctions comptent. L’ajout de NULL puis son remplacement par 0 constituent deux changements de données distincts.

Ce test est réutilisable sur une copie de votre analyse : si l’ajout d’une valeur manquante modifie un résultat censé ne décrire que les valeurs connues, cherchez quelle formule ou transformation a changé ce périmètre.

Que vérifier avant de présenter votre comptage ?

Vérifiez ce que représente une ligne, le périmètre retenu et le sens de l’absence. Un champ non nul n’est pas automatiquement un champ valide : il peut contenir une valeur incorrecte ou, pour du texte, une chaîne vide.

Dans cet exercice, les montants non nuls sont tous numériques. Dans SQLite, déclarer une colonne NUMERIC ne suffit pas à empêcher du texte : AVG peut traiter un texte non numérique comme zéro. Vérifiez les valeurs importées avant d’interpréter la moyenne. La documentation des types SQLite décrit ce fonctionnement ; la fiche AVG citée plus haut précise le traitement du texte.

Dans SQLite et PostgreSQL, une chaîne vide comme '' n’est pas NULL. COUNT sur une colonne de texte peut donc la compter. Votre règle de qualité doit préciser ce qui constitue une valeur utilisable ; le comptage non nul ne fait pas tout ce contrôle.

Pour ces requêtes sans GROUP BY, si aucune ligne n’est retenue, COUNT(*) vaut zéro. Sur les requêtes utilisées ici, AVG(montant) et SUM(montant) renvoient NULL. Si les lignes existent mais que tous leurs montants sont NULL, COUNT(montant) vaut également zéro ; la somme et la moyenne restent NULL. N’affichez pas automatiquement « moyenne de 0 € » lorsque vous n’avez aucune observation numérique.

Avant de partager le résultat

Ces cases servent d’aide-mémoire pendant votre lecture. Pour compléter cette méthode, utilisez nos contrôles avant de présenter un chiffre. Pour calculer par catégorie, notre guide GROUP BY explique le regroupement.

Questions fréquentes sur COUNT et NULL

COUNT(id) est-il toujours équivalent à COUNT(*) ?

Seulement si id n’est jamais NULL dans le résultat compté. C’est le cas dans notre table seule, grâce à la clé primaire. Une jointure externe peut produire des valeurs NULL dans l’identifiant de la table associée.

Faut-il remplacer NULL par zéro pour simplifier le rapport ?

Seulement si une règle confirmée établit que cette absence signifie réellement zéro. Sinon, indiquez ce qui manque et gardez une base de calcul explicite.

COUNT(DISTINCT client) retrouve-t-il les clients manquants ?

Non. Il distingue les identifiants disponibles. Il ne déduit pas celui d’une demande dont le client est absent.

Demandes et montants entièrement fictifs. Requêtes exécutées avec SQLite, calculs contrôlés. Documentation PostgreSQL et SQLite consultée le 13 octobre 2026.

Financez votre formation en toute simplicité

Le financement ne doit jamais être un frein à votre projet.
Chez DataSuits, nos conseillers pédagogiques vous accompagnent à chaque étape pour trouver la meilleure solution de financement adaptée à votre profil:

logo-mon-compte-professionnel-de-formationFrance-travail-2023.svgopco-1

Candidater à l’une de nos formations DataSuits

Remplissez ce court formulaire pour candidater à la formation de votre choix.
Notre équipe pédagogique vous contactera rapidement pour échanger sur votre parcours et vous accompagner dans la suite de votre inscription.

Logo_datasuits

Votre demande a bien été prise en compte. 📚

Prochaine étape 👇
Réservez un échange téléphonique avec un conseiller pour parler de votre projet de formation
Contacter un conseiller
Oups ! Une erreur est survenue lors de l’envoi du formulaire.