Pourquoi le DAX est difficile au début
En SQL, une requête est statique : vous écrivez un filtre et il s'applique. En DAX, la même mesure peut retourner des valeurs complètement différentes selon le contexte dans lequel elle est évaluée. Un visuel, un segment, un filtre de rapport modifient le contexte et donc le résultat de vos mesures.
Il y a deux types de contextes en DAX :
- Le contexte de filtre : l'ensemble des filtres actifs au moment de l'évaluation d'une mesure. Il vient des segments, des filtres de page, des visuels et des relations entre tables.
- Le contexte de ligne : la ligne courante lors d'une itération sur une table (dans les fonctions X comme SUMX, AVERAGEX, MAXX).
CALCULATE : la fonction la plus puissante du DAX
CALCULATE fait deux choses : évalue une expression, et modifie le contexte de filtre dans lequel cette expression est évaluée. C'est sa deuxième fonction qui la rend si puissante et si déroutante.
-- Mesure simple : total des ventes dans le contexte actuel
Total Ventes = SUM(Ventes[Montant])
-- Avec CALCULATE : total des ventes en ignorant le filtre sur la région
Total Ventes Toutes Régions =
CALCULATE(
SUM(Ventes[Montant]),
ALL(Ventes[Région])
)
-- Avec CALCULATE : total des ventes uniquement pour Paris
Total Ventes Paris =
CALCULATE(
SUM(Ventes[Montant]),
Ventes[Région] = "Paris"
)
Dans le premier exemple avec ALL, CALCULATE supprime le filtre sur la colonne Région avant d'évaluer la somme. Dans le second, il ajoute un filtre explicite sur "Paris", quel que soit le contexte externe.
Quand CALCULATE reçoit un filtre explicite sur une colonne, ce filtre remplace le filtre existant sur cette colonne dans le contexte. Il ne s'additionne pas, il remplace. C'est là que beaucoup de bugs de mesures DAX prennent leur source.
FILTER vs filtre direct dans CALCULATE
Il y a deux façons de filtrer dans CALCULATE. La première est un filtre direct (booléen), la seconde utilise la fonction FILTER qui retourne une table.
-- Filtre direct (plus rapide, préférable quand possible)
Ventes France =
CALCULATE(
SUM(Ventes[Montant]),
Pays[Nom] = "France"
)
-- Avec FILTER (nécessaire pour des conditions complexes)
Ventes Gros Clients =
CALCULATE(
SUM(Ventes[Montant]),
FILTER(
Clients,
Clients[CA Annuel] > 100000
)
)
Le filtre direct est plus performant car Power BI peut l'optimiser et l'appliquer directement au niveau de l'index. FILTER itère sur chaque ligne de la table spécifiée, ce qui est plus lent sur de grandes tables. Utilisez FILTER uniquement quand le filtre direct ne suffit pas.
ALL, ALLEXCEPT et ALLSELECTED
Ces trois fonctions sont souvent utilisées dans CALCULATE pour manipuler le contexte de filtre.
-- ALL : supprime tous les filtres sur une table ou une colonne
Part de marché =
DIVIDE(
SUM(Ventes[Montant]),
CALCULATE(SUM(Ventes[Montant]), ALL(Ventes))
)
-- ALLEXCEPT : supprime tous les filtres SAUF sur les colonnes spécifiées
Total par Région (tous produits) =
CALCULATE(
SUM(Ventes[Montant]),
ALLEXCEPT(Ventes, Ventes[Région])
)
-- ALLSELECTED : supprime les filtres internes au visuel
-- mais conserve les filtres du rapport (segments, filtres de page)
Part dans la sélection =
DIVIDE(
SUM(Ventes[Montant]),
CALCULATE(SUM(Ventes[Montant]), ALLSELECTED(Ventes))
)
Les fonctions X et le contexte de ligne
Les fonctions suffixées en X (SUMX, AVERAGEX, MAXX, MINX, COUNTX) itèrent sur chaque ligne d'une table et évaluent une expression pour chaque ligne. C'est là qu'intervient le contexte de ligne.
-- SUM multiplie après avoir sommé
-- Résultat incorrect si les prix varient par ligne
Revenu incorrect = SUM(Ventes[Quantité]) * SUM(Ventes[Prix Unitaire])
-- SUMX multiplie d'abord pour chaque ligne, puis somme
-- C'est le calcul correct
Revenu correct =
SUMX(
Ventes,
Ventes[Quantité] * Ventes[Prix Unitaire]
)
La transition de contexte : le concept le plus avancé
La transition de contexte se produit quand CALCULATE est utilisé à l'intérieur d'une itération (fonction X). Dans ce cas, CALCULATE convertit automatiquement le contexte de ligne en contexte de filtre. C'est subtil mais crucial pour comprendre certains comportements inattendus.
-- Exemple de transition de contexte
Ventes Cumulées =
SUMX(
Dates,
CALCULATE(SUM(Ventes[Montant]))
-- Ici, CALCULATE déclenche une transition de contexte :
-- la ligne courante de Dates devient un filtre
-- Résultat : on obtient les ventes pour chaque date
)
Mesures calculées vs colonnes calculées : quand utiliser quoi
Une colonne calculée est évaluée au chargement des données, pour chaque ligne, dans un contexte de ligne. Une mesure est évaluée à la demande, dans le contexte de filtre du visuel.
- Utilisez une colonne calculée quand vous avez besoin d'une valeur par ligne (catégorie, segment, valeur dérivée) pour l'utiliser dans des filtres ou des axes
- Utilisez une mesure pour tous les calculs agrégés (sommes, moyennes, pourcentages, variations)
Les mesures sont généralement préférables car elles ne stockent pas de données supplémentaires dans le modèle et s'adaptent automatiquement au contexte du visuel.
Déboguer une mesure DAX
Quand une mesure retourne une valeur inattendue, voici la méthode que j'utilise systématiquement : créer une table de débogage dans Power BI avec DAX Studio, qui permet d'évaluer vos mesures dans différents contextes sans affecter le rapport. Visualiser la table filtrée que voit votre mesure résout souvent le problème immédiatement.