DAX : le chiffre faux qui a l'air juste
Trois mécanismes de DAX renvoient un nombre parfaitement plausible quand on les écrit de travers : une variable figée, un filtre qui remplace au lieu de croiser, une mesure qui ne voit pas la ligne en cours. Voici comment les reconnaître, sur un grand livre de deux exercices.

Dans le cadre de la rubrique « Je partage mes connaissances », je vous propose de regarder trois mécanismes de DAX qui partagent un défaut désagréable : mal écrits, ils ne renvoient pas d'erreur. Ils renvoient un nombre. Un nombre du bon ordre de grandeur, correctement formaté, qui passe sans encombre la relecture d'un comité de direction.
Le terrain reste le même que dans les articles précédents : un grand livre, un plan comptable, un budget. Le grand livre porte cette fois deux exercices, 2025 et 2026, soit 54 écritures équilibrées. Toutes les valeurs citées ici sortent de ce fichier et se revérifient.

Une variable est une valeur, une mesure est une recette
Une variable DAX se déclare avant le RETURN. Elle vaut ce qu'elle valait au moment de sa déclaration, dans le contexte de ce moment-là. C'est ce qui la rend utile, et c'est aussi ce qui piège.
Utile, pour deux raisons. La première tient à la performance : écrire DIVIDE ( [Produits] - [Charges], [Produits] ) demande le calcul de [Produits] deux fois. Sur 54 lignes, personne ne le voit. Sur un grand livre de deux millions de lignes, le temps de réponse du visuel double. La seconde tient au débogage : on remplace momentanément le RETURN par le nom d'une variable pour lire ce que vaut réellement l'étape intermédiaire. C'est la seule façon pratique d'inspecter le milieu d'une mesure longue.
Le piège, maintenant. Cette mesure paraît normale et elle est fausse :
// FAUX : ne renvoie pas les charges de l'exercice précédent
Charges N-1 faux =
VAR Chg = [Charges]
RETURN
CALCULATE ( Chg, SAMEPERIODLASTYEAR ( Calendrier[Date] ) )
Chg a été calculé avant que CALCULATE ne change le contexte. La mesure renvoie donc 65 585,50, les charges de 2026, alors qu'on lui demandait celles de 2025. Rien ne le signale : le montant est plausible, il s'affiche, il part dans le rapport. La forme juste met la mesure, et non la variable, à l'intérieur de CALCULATE :
Charges N-1 =
CALCULATE ( [Charges], SAMEPERIODLASTYEAR ( Calendrier[Date] ) )
Elle renvoie 57 379,90, qui est bien le total des charges de 2025.
Une variable est une valeur, une mesure est une recette. CALCULATE sait refaire une recette ; il ne sait pas changer une valeur déjà servie.
Le filtre qui remplace, et celui qui croise
Deuxième mécanisme. Un filtre passé nu à CALCULATE ne s'ajoute pas au filtre déjà présent : il le remplace, colonne par colonne. Prenons une mesure des charges de personnel, écrite des deux façons.
// Écrase le filtre de la ligne
Charges personnel ecrase =
CALCULATE ( [Charges], PlanComptable[Compte] = "641000" )
// Croise avec le filtre de la ligne
Charges personnel croise =
CALCULATE ( [Charges], KEEPFILTERS ( PlanComptable[Compte] = "641000" ) )
Posez-les côte à côte dans un tableau découpé par compte. La première affiche 45 000,00 sur toutes les lignes, y compris sur les achats de matières premières et sur les locations, parce que le filtre de compte venu du visuel a été écrasé. La seconde n'affiche 45 000,00 que sur la ligne 641000, et rien ailleurs.

La version écrasée n'est pas une erreur de syntaxe, et elle ne provoque aucun avertissement. Elle produit un tableau où chaque compte semble porter la masse salariale. Quand un montant identique se répète sur toutes les lignes d'un tableau, c'est le premier endroit à regarder.
Ce que l'on retire, ce que l'on garde
Les modificateurs de CALCULATE se choisissent en répondant à une seule question : quel filtre je retire, et lequel je garde ?
| Fonction | Ce qu'elle fait | Quand la choisir |
|---|---|---|
| ALL ( Table ) | Retire tous les filtres de la table | Un dénominateur qui doit ignorer la sélection |
| REMOVEFILTERS ( Table ) | Identique à ALL, mais ne renvoie pas de table | En modificateur de CALCULATE : le nom dit l'intention |
| ALLEXCEPT ( Table, Col ) | Retire tous les filtres sauf ceux de la colonne citée | Un total par catégorie, tous sous-niveaux confondus |
| ALLSELECTED ( ) | Retire les filtres du visuel, garde ceux des segments | Un pourcentage qui doit suivre le filtrage de la page |
| KEEPFILTERS ( Cond ) | Ajoute la condition sans écraser le filtre existant | Croiser une condition avec la sélection |
La différence entre les deux premières lignes et la quatrième se voit dès qu'un segment est posé sur la page. Deux mesures, la même intention apparente :
Total charges toutes annees =
CALCULATE ( [Charges], REMOVEFILTERS ( Calendrier ) )
Total charges selection =
CALCULATE ( [Charges], ALLSELECTED ( Calendrier ) )

| Mesure | Sans segment | Segment sur 2026 |
|---|---|---|
| Total charges toutes années | 122 965,40 | 122 965,40 |
| Total charges sélection | 122 965,40 | 65 585,50 |
122 965,40 est bien le cumul des deux exercices : 57 379,90 plus 65 585,50. REMOVEFILTERS ignore tout, y compris ce que l'utilisateur vient de demander. ALLSELECTED n'ignore que le découpage du visuel. Pour un pourcentage affiché à côté d'un segment, c'est presque toujours ALLSELECTED qu'il faut écrire, et presque toujours ALL qui est écrit par réflexe. Le symptôme, là encore, est discret : les pourcentages cessent de totaliser 100 % dès qu'une sélection est faite.
Quand une ligne devient un filtre
Troisième mécanisme, le plus rentable et le plus mal compris. La règle tient en une phrase : CALCULATE placé dans un contexte de ligne transforme cette ligne en filtre. On appelle cela la transition de contexte.
Un exemple concret : compter les pièces comptables dont les charges dépassent 20 000 euros, sur les deux exercices.
Nombre de pieces deficitaires =
COUNTROWS (
FILTER (
VALUES ( GrandLivre[Piece] ),
CALCULATE ( [Charges] ) > 20000
)
)
FILTER établit un contexte de ligne sur chaque pièce. Sans le CALCULATE autour de [Charges], la mesure ne verrait pas la pièce en cours : elle renverrait le total du contexte extérieur pour toutes les lignes, et la condition serait vraie partout ou fausse partout. Avec CALCULATE, la pièce courante devient un filtre et la comparaison a un sens.
Sur ce grand livre, la mesure renvoie 4. Ce sont les quatre écritures de paie, et elles seules :
| Pièce | Charges portées par la pièce |
|---|---|
| OD-2026-002 | 32 100,00 |
| OD-2025-002 | 25 680,00 |
| OD-2026-005 | 22 500,00 |
| OD-2025-005 | 21 375,00 |
La cinquième pièce la plus lourde ne pèse que 3 200,50 : entre la paie et tout le reste, l'écart est d'un facteur sept. C'est une bonne raison de ne pas deviner ce genre de compte à l'ordre de grandeur.
Le raccourci à retenir : écrire le nom d'une mesure dans un itérateur déclenche déjà la transition de contexte, le CALCULATE est implicite. Écrire une expression ne la déclenche pas. C'est pour cela que deux formules qui se ressemblent à s'y méprendre ne donnent pas le même résultat, et c'est le premier endroit à regarder quand un chiffre reste inexplicablement constant sur toutes les lignes d'un tableau.
Le contrôle qui doit tomber juste
Rien de ce qui précède ne tient si le modèle lui-même est faux. Avant d'écrire la moindre mesure avancée, posez un tableau avec l'année en colonnes et trois mesures de base. Vous devez lire exactement ceci :
| Mesure | 2025 | 2026 |
|---|---|---|
| Produits | 22 460,00 | 23 800,00 |
| Charges | 57 379,90 | 65 585,50 |
| Résultat | -34 919,90 | -41 785,50 |
Deux détails décident de ces six nombres. Le premier : le sens du solde est inversé entre charges et produits. Une charge augmente au débit, un produit augmente au crédit ; écrire la même soustraction pour les deux donne des produits négatifs et un résultat faux du double. Le second : le filtre de classe porte sur le plan comptable, pas sur le grand livre, et il ne fonctionne que parce que la relation entre les deux tables propage le filtre. Sans cette relation, la mesure renvoie le total de toutes les classes, sans prévenir.
Un nombre qui ne provoque pas d'erreur n'est pas un nombre vérifié. Le contrôle, c'est une valeur attendue, calculée à part, que le modèle doit reproduire.
Ces trois mécanismes ont la même signature. Ils ne cassent rien, ils ne remontent rien, et ils déplacent un montant de quelques milliers d'euros dans un rapport que personne ne rejouera. C'est exactement pour cela qu'ils méritent d'être reconnus à l'œil.
L'article suivant met ces mécanismes au travail sur la comparaison de deux exercices : le cumul depuis janvier, le même mois de l'exercice précédent, l'écart en pourcentage, et une moyenne mobile qui se trompe de bornes sans le dire. Lire le 31 janvier qui s'invite dans la moyenne mobile.
Versions : article rédigé d'après Power BI Desktop, mise à jour d'août 2026 (interface en français). Les fonctions DAX utilisées (CALCULATE, DIVIDE, ALLSELECTED, ALL, REMOVEFILTERS, FILTER, SAMEPERIODLASTYEAR) sont disponibles dans les versions actuelles ; les noms de menus peuvent changer au fil des mises à jour mensuelles.