StraFormationStraFormation

SQL : comptez-vous des clients actifs, ou seulement des commandes ?

Illustration peinte : deux mains regroupent plusieurs bons C01 dans le même dossier client, à côté d’un dossier C02 et d’un écran SQL.
SQLAnalyse de donnéesReportingFormation professionnelle

Cinq commandes ne font pas forcément cinq clients. Et une requête qui s’exécute sans erreur ne garantit pas que votre indicateur répond à la question posée. Pour compter des clients actifs, il faut définir l’activité retenue, sélectionner la bonne période et compter les identifiants clients distincts. Il faut aussi rendre visibles les commandes dont le client n’est pas renseigné.

Vous préparez un reporting commercial, vous contrôlez un tableau de bord ou vous devez expliquer un écart à votre responsable ? Voici un exemple que vous pouvez vérifier à la main, puis exécuter en SQL. Il montre comment passer d’un nombre plausible à un résultat que vous savez expliquer.

Le jeu de données et les situations ci-dessous sont fictifs. Ils servent à démontrer un mécanisme technique ; ils ne décrivent pas les résultats d’une entreprise cliente. La couverture est une illustration générée représentant le regroupement de plusieurs commandes par client.

Avant la requête, mettez-vous d’accord sur le mot « actif »

Imaginez cette demande : « Il me faut le nombre de clients actifs en avril. » Pour la personne qui prépare le fichier, cela signifie peut-être « au moins une commande ». Pour le responsable commercial, « au moins une commande payée ». Pour une équipe chargée des abonnements, cela pourrait désigner un contrat en cours, même sans nouvelle commande.

Ces définitions répondent à des questions différentes. Choisir COUNT ou COUNT(DISTINCT) ne tranche pas ce désaccord.

Dans notre exercice, la définition est volontairement précise :

Nous comptons les identifiants clients connus associés à au moins une commande datée d’avril 2026, dont le statut est « payée » dans l’extrait étudié.

Ce n’est pas le nombre de paiements encaissés en avril. Ce n’est pas non plus une photographie garantie de la situation au 30 avril : le statut présent dans un extrait peut avoir changé depuis. Pour répondre à ces autres questions, il faudrait une date de paiement ou un historique adapté.

Cette distinction sert directement trois interlocuteurs :

Votre rôleCe que vous devez pouvoir expliquer
Analyste métier ou chargé de reportingPourquoi une ligne est incluse ou exclue, et quelle entité le résultat compte.
Contrôleur de gestionQuelle date et quel statut définissent le périmètre ; pourquoi deux extractions peuvent différer.
Responsable commercial ou de serviceCe que l’indicateur permet de comparer, et les données manquantes qui limitent son interprétation.

Sept lignes, quatre résultats différents

Voici l’extrait de départ. Chaque ligne représente une commande, identifiée par un numéro unique. NULL signifie ici que l’identifiant client manque.

CommandeClientDate de commandeStatut
F001C012026-04-01payee
F002C012026-04-02payee
F003C022026-04-03payee
F004C032026-04-04annulee
F005NULL2026-04-05payee
F006C042026-03-31payee
F007C022026-04-07payee

Nous écartons F004, annulée, et F006, datée de mars. Restent F001, F002, F003, F005 et F007 : cinq commandes.

Les documentations de SQLite sur les agrégats et de PostgreSQL sur les fonctions d’agrégation distinguent le comptage des lignes et celui des valeurs non nulles. Dans SQLite, DISTINCT retire les valeurs répétées avant le comptage.

Appliqué à notre périmètre, cela donne :

ExpressionRésultatCe que le nombre désigne
COUNT(*)5Les lignes retenues, ici cinq commandes.
COUNT(client_id)4Les lignes dont l’identifiant client est renseigné. C01 et C02 apparaissent chacun deux fois.
COUNT(DISTINCT client_id)2Les identifiants clients différents et renseignés : C01 et C02.
COUNT(CASE WHEN client_id IS NULL THEN 1 END)1La ligne retenue sans identifiant client.

Le résultat explicable est donc : « 2 identifiants clients distincts connus, sur 5 commandes retenues, dont 1 sans identifiant client. »

Dire simplement « nous avons deux clients actifs » effacerait une limite : F005 appartient peut-être à C01, à C02 ou à une autre personne. Cet extrait ne permet pas de le déterminer.

Si vous devez afficher chaque client du portefeuille, y compris ceux qui n’ont rien commandé, poursuivez avec le guide SQL : conserver les clients sans commande avec LEFT JOIN. Il traite la construction de cette population complète.

La fiche de définition du comptage

Avant de transmettre la requête, remplissez cette fiche avec le responsable de l’indicateur. Elle peut accompagner un reporting ou servir de brief pour un exercice de formation.

Point à préciserRéponse dans notre exempleÀ renseigner dans votre cas
Objet comptéIdentifiants clients distincts connusPersonnes, entreprises, comptes, contrats… ?
Activité retenueAu moins une commande au statut payee dans l’extraitQuel événement ou état rend l’entité active ?
Date utiliséeDate de commandeDate de commande, paiement, livraison, début de contrat… ?
PériodeDu 1er avril inclus au 1er mai excluBornes, type de date et fuseau si des heures sont présentes.
Ce que représente une ligneUne commandeCommande, ligne de produit, paiement, événement… ?
Identifiantclient_id, supposé stable dans cet exerciceUne même entité peut-elle avoir plusieurs codes ?
Donnée manquanteCommande conservée, absence de client comptée séparémentCombien de cas, et qui peut les clarifier ?
État de la sourceStatut présent dans l’extrait fictifDate d’extraction, version et éventuel historique.

Une fiche incomplète signale une question à résoudre, pas une faute du salarié qui produit le tableau. Par exemple, si deux services utilisent des dates différentes, demandez-leur d’abord quelle décision leur indicateur doit éclairer. Réécrire la requête sans cet accord risque seulement de déplacer l’écart.

Une requête complète à essayer sur les données fictives

Le code suivant est autonome : il crée un jeu de données temporaire dans la requête, sans accéder à vos tables. Il a été exécuté pour cet article avec SQLite 3.53.1. La syntaxe des dates et des jeux de données intégrés doit être adaptée avant utilisation dans un autre moteur.

WITH nomme ici deux étapes lisibles : les commandes, puis le périmètre retenu. La documentation SQLite sur les expressions WITH décrit ce principe de résultats temporaires utilisés pendant une instruction. Le filtrage WHERE sélectionne les lignes avant le calcul des agrégats.

WITH commandes (
    commande_id, client_id, date_commande, statut
) AS (
    VALUES
        ('F001', 'C01', '2026-04-01', 'payee'),
        ('F002', 'C01', '2026-04-02', 'payee'),
        ('F003', 'C02', '2026-04-03', 'payee'),
        ('F004', 'C03', '2026-04-04', 'annulee'),
        ('F005', NULL,  '2026-04-05', 'payee'),
        ('F006', 'C04', '2026-03-31', 'payee'),
        ('F007', 'C02', '2026-04-07', 'payee')
),
perimetre AS (
    SELECT commande_id, client_id
    FROM commandes
    WHERE date_commande >= '2026-04-01'
      AND date_commande <  '2026-05-01'
      AND statut = 'payee'
)
SELECT
    COUNT(*) AS lignes_retenues,
    COUNT(DISTINCT commande_id) AS commandes_distinctes,
    COUNT(client_id) AS lignes_client_renseigne,
    COUNT(DISTINCT client_id) AS clients_distincts_connus,
    COUNT(CASE WHEN client_id IS NULL THEN 1 END)
        AS lignes_client_manquant
FROM perimetre;

Le résultat, dans l’ordre des colonnes, est 5 — 5 — 4 — 2 — 1.

Les dates de ce jeu sont des textes au format AAAA-MM-JJ, sans heure. Cette convention suffit pour l’exercice. Sur votre système, vérifiez le type réel du champ et les règles applicables aux heures avant de reprendre le filtre.

La deuxième colonne apporte un contrôle supplémentaire : ici, cinq lignes correspondent à cinq numéros de commande différents. Si vous obtenez six lignes pour cinq commandes, vérifiez ce que représente une ligne avant de conclure à une erreur. Une commande comportant plusieurs produits peut légitimement occuper plusieurs lignes dans une autre table.

Trois raccourcis qui donnent un chiffre propre, mais trompeur

1. Remplacer le client manquant par « INCONNU ». Avec COUNT(DISTINCT COALESCE(client_id, 'INCONNU')), notre résultat passe à trois : COALESCE remplace ici la valeur nulle par cette étiquette. Vous avez créé une catégorie supplémentaire, pas identifié un troisième client. Cette étiquette peut servir à présenter les absences ; elle ne doit pas devenir une personne fictive dans l’indicateur.

2. Ajouter DISTINCT pour considérer le dossier réglé. Si F001 est accidentellement répétée, le nombre de clients distincts reste deux. Le résultat semble stable, mais la source comporte désormais six lignes pour cinq commandes. Le comptage des clients ne certifie donc pas la qualité de tout le fichier. Si l’écart apparaît après un rapprochement de tables, le guide Power Query : ajouter ou fusionner vos tables explique un autre problème : la multiplication des lignes lors d’une fusion.

3. Compter des noms au lieu d’identifiants fiables. Dans un exemple fictif, « Martin SARL » et « MARTIN » peuvent désigner le même compte ; deux comptes distincts peuvent aussi porter un nom proche. DISTINCT distingue les valeurs fournies. Il ne décide pas quelles fiches correspondent à la même entité. Cette règle d’identité doit être clarifiée avec la personne responsable du référentiel.

Vérifiez que vous savez interpréter le résultat

Reprenez les cinq commandes du périmètre. Pour chaque situation ci-dessous, repartez de l’extrait initial : les modifications ne se cumulent pas.

Modification fictiveRésultat attenduExplication
Une nouvelle commande payée d’avril pour C016 commandes, 2 clients connus, 1 commande sans clientC01 était déjà compté.
Une nouvelle commande payée d’avril pour C056 commandes, 3 clients connus, 1 commande sans clientUn nouvel identifiant apparaît.
Une nouvelle commande payée d’avril sans client6 commandes, 2 clients connus, 2 commandes sans clientL’incertitude augmente, sans client supplémentaire identifié.
Toutes les commandes du périmètre ont un client manquant5 commandes, 0 client connu, 5 commandes sans clientZéro client identifié ne prouve pas une absence d’activité.

Ces variantes ont été exécutées sur le jeu fictif. Elles ne constituent pas un test de votre base de données.

Pour le responsable qui relit le reporting, trois questions suffisent à engager un contrôle utile : que compte le nombre, quelles lignes ont été retenues, et que reste-t-il impossible à savoir ? Demander ces explications permet aussi de préciser la compétence à développer chez la personne qui prépare les données.

Quelle formation SQL correspond à cette difficulté ?

Si vous savez utiliser des tableaux mais dépendez d’une requête copiée pour filtrer et compter, travailler les fondations peut être plus utile que commencer par des fonctions avancées.

La formation SQL pour l’analyse de données de StraFormation propose deux parcours de 21 heures, après positionnement :

  • Fondations & analyse : pour apprendre à sélectionner, filtrer, agréger et rapprocher des données. Les prérequis portent sur les tableaux structurés, les filtres et les calculs simples ; la programmation préalable n’est pas exigée.
  • SQL analytique avancé : pour les personnes déjà autonomes avec SELECT, WHERE, GROUP BY, HAVING et les jointures entre deux tables. Le programme approfondit notamment les requêtes structurées avec WITH, les fonctions de fenêtre et les contrôles de qualité.

La page prévoit Strasbourg ou la distance, avec moteur, version et accès à préciser. Il s’agit d’apprentissage sur des données fictives ou autorisées, pas d’une prestation de modification de votre base de production. Les dates, le devis et les conditions du parcours restent à confirmer.

Pour demander un parcours adapté, indiquez votre rôle, la question métier que vous voulez résoudre, votre moteur SQL si vous le connaissez, ce que vous savez déjà écrire et ce que vous devez encore faire vérifier. Pour une équipe, ajoutez le nombre de participants, leurs niveaux et l’échéance du projet. Un exemple fictif décrivant les colonnes et le résultat attendu suffit pour engager cet échange ; aucun fichier client n’est nécessaire.

Vous pourrez ainsi discuter d’un objectif observable : produire une requête, expliquer son périmètre et documenter les limites du chiffre obtenu.

4.8/5

225+ avis Google

Qualiopi

Certifié qualité

Éligible CPF

100% finançable

5000+

Apprenants formés

Formations recommandées

Articles pour aller plus loin