Lavergne

DAX Design pattern

2026-05-22

Ceci est un article perpétuel, qui sera compété au fil du temps et des idées.

Syntaxe et convention de nommage

Lorsque j’écris du code DAX, je suis quelques règles de syntaxe afin d’avoir un code propre et lisible. Pour autant je ne m’impose pas une indentation stricte ; pour les instructions les plus simples j’écris mon code sur une seule ligne.

Pour mettre en forme rapidement le code DAX ; je ne peux que conseiller le très utile DAX Formatter.

Optimisation et choix des fonctions

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.

🡻 devient 🡻

VAR _mesure_test_2 = [mesure_test_2]
RETURN SWITCH(TRUE()
    , NOT(ISBLANK([mesure_test])), 0
    , _mesure_test_2 > 1000), -1
    , _mesure_test_2
)

🡻 devient 🡻

MIN(COALESCE([mesure_test], 0), 1000)

Design pattern de mesures

Date et temps

Voici quelques exemples de mesures pour des cas d’usage génériques :

Convertir une durée en secondes vers le type time

La mesure renvoie une valeur de type DateTime correspondant au nombre de secondes donné par la mesure source. Si la durée dépasse 24 heures (86 400 secondes) la mesure renvoie le modulo à la journée.

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)

Comptage

Compter le nombre d’utilisateurs sur une période

user_nb = DISTINCTCOUNT(t_fact_app_usage[user_principal_name])

Compter le nombre de nouveaux utilisateurs

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))

Compter le nombre d’utilisateurs réguliers

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))

Compter le nombre d’utilisateurs perdus

Le nombre d’utilisateurs avec 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)))