2026-05-22
Ceci est un article perpétuel, qui sera complété au fil du temps et des idées.
Lorsque j’écris du code DAX, je respecte quelques règles de syntaxe afin d’avoir un code propre et lisible. Pour autant, je ne m’impose pas d’indentation stricte ; pour les instructions les plus simples j’écris mon code sur une seule ligne.
t_cal = CALENDAR(DATE(2020, 1, 1), TODAY())t_cal = CALENDAR(DATE(2020, 1, 1), EOMONTH(MAX(t_fact[date_fact]), 0) )VAR _varDate = MAX(dim_calendrier[jour])Pour mettre en forme rapidement le code DAX, je ne peux que conseiller le très utile DAX Formatter.
Comme pour beaucoup de choses, il existe de nombreuses méthodes pour arriver au même résultat. Mais certains chemins sont plus courts que d’autres. Voici quelques astuces pour avoir un code performant et maintenable.
IF([mesure_test], 0, IF([mesure_test_2] > 1000, -1, [mesure_test_2]))
🡻 devient 🡻
VAR _mesure_test_2 = [mesure_test_2]
RETURN SWITCH(TRUE()
, NOT(ISBLANK([mesure_test])), 0
, _mesure_test_2 > 1000, -1
, _mesure_test_2
)
VAR _mesure_test = [mesure_test]
RETURN IF(ISBLANK(_mesure_test), 0, IF(_mesure_test > 1000, 1000, _mesure_test))
🡻 devient 🡻
MIN(COALESCE([mesure_test], 0), 1000)
Voici quelques exemples de mesures pour des cas d’usage génériques :
La mesure renvoie une valeur de type DateTime correspondant au nombre de secondes donné par la mesure source. Elle doit être mise au format hh:MM:ss dans le paramétrage de la mesure pour renvoyer une information cohérente. Si la durée dépasse 24 heures (86 400 secondes), la mesure renvoie le modulo à la journée.
La fonction TIME reçoit en paramètres des valeurs numériques de type short : de -32 768 à 32 767. Les valeurs utilisées ne doivent donc pas dépasser 32 767 (sachant que 32 767 secondes ça fait 9 heures 6 minutes et 7 secondes).
Si la valeur est inférieure à 32 768 :
ValTime = TIME(0, 0, [ValSelected])
Si la valeur est supérieure ou égale à 32 768 :
ValTime = VAR _v = [ValSelected]
VAR _h = FLOOR(DIVIDE(_v, 3600), 1)
VAR _m = FLOOR(DIVIDE(MOD(_v, 3600), 60), 1)
VAR _s = MOD(_v, 60)
RETURN TIME(_h, _m, _s)
On utilise la fonction FORMAT qui permet de faire une conversion vers du texte. Attention, une valeur sous forme de texte ne peut plus être utilisée dans un visuel graphique (histogramme, courbe, camembert, etc.).
TextTime = FORMAT([ValTime], "HH:mm:ss"))
Si la valeur est encore en secondes (valeur numérique) :
TextTime = VAR _v = [ValSelected]
VAR _h = FLOOR(DIVIDE(_v, 3600), 1)
VAR _m = FLOOR(DIVIDE(MOD(_v, 3600), 60), 1)
VAR _s = MOD(_v, 60)
RETURN FORMAT(_h, "00") & ":" & FORMAT(_m, "00") & ":" & FORMAT(_s, "00")
user_nb = DISTINCTCOUNT(t_fact_app_usage[user_principal_name])
Le nombre d’utilisateurs enregistrés pour la première fois sur la période observée.
user_new_nb = VAR _current = DISTINCT(t_fact_app_usage[user_principal_name])
VAR _previous = CALCULATETABLE(DISTINCT(t_fact_app_usage[user_principal_name])
, FILTER(ALL(t_dim_calendrier), t_dim_calendrier[dt_date] < MIN(t_dim_calendrier[dt_date]))
)
RETURN COUNTROWS(EXCEPT(_current, _previous))
Le nombre d’utilisateurs enregistrés sur la période observée et qui ont au moins un autre enregistrement avant le début de la période observée.
user_old_nb = VAR _current = DISTINCT(t_fact_app_usage[user_principal_name])
VAR _previous = CALCULATETABLE(DISTINCT(t_fact_app_usage[user_principal_name])
, FILTER(ALL(t_dim_calendrier), t_dim_calendrier[dt_date] < MIN(t_dim_calendrier[dt_date]))
)
RETURN COUNTROWS(INTERSECT(_current, _previous))
Le nombre d’utilisateurs ayant au moins un enregistrement avant le début de la période observée et qui n’ont plus aucun enregistrement à partir du début de la période observée.
user_lost_nb = VAR _current = CALCULATETABLE(DISTINCT(t_fact_app_usage[user_principal_name])
, FILTER(ALL(t_dim_calendrier), t_dim_calendrier[dt_date] >= MIN(t_dim_calendrier[dt_date]))
)
VAR _previous = CALCULATETABLE(DISTINCT(t_fact_app_usage[user_principal_name])
, FILTER(ALL(t_dim_calendrier), t_dim_calendrier[dt_date] < MIN(t_dim_calendrier[dt_date]))
)
RETURN COUNTROWS(EXCEPT(_previous, _current))
On utilise une mesure (qu’on appellera hexa_alea) qui renvoie une valeur hexadécimale aléatoire entre 0 et F (15).
MEASURE 'Measures'[hexa_alea] = VAR _an = RANDBETWEEN(0, 15)
RETURN IF(_an < 10, FORMAT(_an, "0"), UNICHAR(UNICODE("A") + _an - 10))
La mesure hexa_alea doit être appelée dans un CALCULATE avec une table et être enregistrée dans une variable pour forcer plusieurs évaluations successives et ainsi obtenir des valeurs diférentes.
MEASURE 'Measures'[color_alea] = VAR _a = [hexa_alea]
VAR _b = CALCULATE([hexa_alea], GENERATESERIES(0, 0, 1))
VAR _c = CALCULATE([hexa_alea], GENERATESERIES(0, 0, 1))
VAR _d = CALCULATE([hexa_alea], GENERATESERIES(0, 0, 1))
VAR _e = CALCULATE([hexa_alea], GENERATESERIES(0, 0, 1))
VAR _f = CALCULATE([hexa_alea], GENERATESERIES(0, 0, 1))
RETURN "#" & _a &_b & _c & _d & _e & _f
Il aurait été plus élégant d’utiliser un GENERATESERIES pour éviter la succession de variables. Mais dans ce cas, le contexte d’exécution est unique et RANDBETWEEN renvoie toujours du gris :
MEASURE 'Measures'[color_alea_ko] = "#"
& CONCATENATEX(
ADDCOLUMNS(GENERATESERIES(0, 5)
, "h", CALCULATE([hexa_alea], GENERATESERIES(0, 0, 1))
) , [h])
Le résultat sera toujours de la forme #DDDDDD, #555555, etc.
Cette mesure renvoie le code hexadécimal d’une couleur au hasard. La couleur a une luminosité constante de 51 % et une dominante rouge, verte ou bleue pour être toujours visible.
MEASURE 'Measures'[color51_alea] =
VAR _pos = MOD(SECOND(UTCNOW()),6) + 1 -- RANDBETWEEN(1, 3)
VAR _ab = RANDBETWEEN(3, 255)
VAR _an = MOD(_ab, 16)
VAR _at = IF(_an < 10, FORMAT(_an, "0"), UNICHAR(UNICODE("A") + _an - 10))
VAR _bn = FLOOR(DIVIDE(_ab, 16), 1)
VAR _bt = IF(_bn < 10, FORMAT(_bn, "0"), UNICHAR(UNICODE("A") + _bn - 10))
RETURN "#"
& SWITCH(_pos, 1, "FF03", 2, "03FF", 3, "FF", 4, "03")
& _at & _bt
& SWITCH(_pos, 3, "03", 4, "FF", 5, "FF03", 6, "03FF")
Le format Base64 permet de sérialiser une image pour la stocker directement dans un champ texte. Power BI est capable d’interpréter ce format.
data:image/png;base64,

Le Scalable Vector Graphics (en français “graphique vectoriel adaptable”), ou SVG, est un format de données ASCII conçu pour décrire des ensembles de graphiques vectoriels 2D et fondé sur XML. cf.
Ce format a l’avantage d’être facilement manipulable et paramétrable. Il est donc très utile pour créer des visuels personnalisés. SQLBI l’explique très bien dans cet article.
<svg> et </svg>, et répéter toutes les doubles quotes pour qu’elles ne soient pas interprétées dans une mesure (ctrl+H est ton ami …).<svg>) le code suivant : data:image/svg+xml;utf8,