Aller au contenu

Intelligence temporelle (YoY, PoP, YTD, glissants déclaratifs)

Mondrian-4 prend en charge un élément de schema <TimeCalc> qui déclare les métriques d’intelligence temporelle courantes. Le chargeur de schema désucrit chaque déclaration en un <CalculatedMember> validé sur [Measures] — vous énoncez donc ce que vous voulez plutôt que d’écrire et maintenir des formules MDX à la main.

Pourquoi l’intelligence temporelle déclarative ?

Sans <TimeCalc>, la croissance year-over-year nécessite un membre calculé comme :

<CalculatedMember name="Revenue YoY" dimension="Measures">
<Formula>
([Measures].[Revenue] - (ParallelPeriod([Calendar].[Year], 1, [Calendar].CurrentMember),
[Measures].[Revenue]))
/ (ParallelPeriod([Calendar].[Year], 1, [Calendar].CurrentMember),
[Measures].[Revenue])
</Formula>
<CalculatedMemberProperty name="FORMAT_STRING" value="0.0%"/>
</CalculatedMember>

Avec <TimeCalc>, la même métrique est :

<TimeCalc name="Revenue YoY" type="yoy" measure="Revenue"
timeDimension="Calendar" formatString="0.0%"/>

Le chargeur génère le MDX pour vous, valide que la mesure et la dimension temporelle référencées existent, et lève une erreur au moment du chargement plutôt que de produire un résultat silencieusement faux.

Prérequis : une dimension Time typée

<TimeCalc> nécessite que le cube ait une dimension Time typée — une <Dimension> avec type="TIME" dont la hiérarchie a des niveaux nommés pour année, trimestre et mois. Le niveau année doit porter levelType="TimeYears", et les niveaux trimestre et mois doivent porter respectivement levelType="TimeQuarters" et levelType="TimeMonths". Les calculs intra-année (ytd, pop, rolling) nécessitent au minimum un niveau mois dans la hiérarchie.

Une dimension Calendar minimale qui satisfait l’exigence :

<Dimension name="Calendar" type="TIME" table="dim_date" key="Date">
<Attributes>
<Attribute name="Year" keyColumn="year_num" levelType="TimeYears"/>
<Attribute name="Quarter" keyColumn="quarter_key" levelType="TimeQuarters"/>
<Attribute name="Month" keyColumn="month_key" levelType="TimeMonths"/>
<Attribute name="Date" keyColumn="date_key" levelType="TimeDays"/>
</Attributes>
<Hierarchies>
<Hierarchy name="Calendar" allMemberName="All Time">
<Level attribute="Year"/>
<Level attribute="Quarter"/>
<Level attribute="Month"/>
<Level attribute="Date"/>
</Hierarchy>
</Hierarchies>
</Dimension>

Placement dans le schema

Les éléments <TimeCalc> sont enveloppés dans un bloc <TimeCalcs> à l’intérieur d’un <Cube>, au même niveau que <CalculatedMembers> :

<Cube name="Monthly Revenue">
<Dimensions>
<Dimension source="Calendar"/>
<!-- other dimensions -->
</Dimensions>
<MeasureGroups>
<MeasureGroup name="Revenue" table="monthly_revenue_fact">
<Measures>
<Measure name="Revenue" column="revenue" aggregator="sum"/>
</Measures>
<DimensionLinks>
<ForeignKeyLink dimension="Calendar" foreignKeyColumn="month_key"/>
</DimensionLinks>
</MeasureGroup>
</MeasureGroups>
<TimeCalcs>
<TimeCalc name="Revenue YoY" type="yoy" measure="Revenue" timeDimension="Calendar" formatString="0.0%"/>
<TimeCalc name="Revenue PoP" type="pop" measure="Revenue" timeDimension="Calendar" formatString="0.0%"/>
<TimeCalc name="Revenue YTD" type="ytd" measure="Revenue" timeDimension="Calendar"/>
<TimeCalc name="Revenue R3" type="rolling" measure="Revenue" timeDimension="Calendar" window="3" function="avg"/>
</TimeCalcs>
</Cube>

Référence des attributs

Attributclé XML / YAMLRequisDescription
namenameouiLe nom du membre calculé généré. Apparaît dans [Measures] comme toute autre mesure.
typetypeouiLe type de métrique : yoy, pop, ytd ou rolling. Voir Types de métrique ci-dessous.
measuremeasureouiLe nom d’une <Measure> existante dans le cube. Le chargeur rejette une mesure inconnue au chargement du schema.
timeDimensiontime_dimensionconditionnelLe nom d’une dimension type="TIME". Peut être omis quand le cube a exactement une dimension TIME ; requis quand il en a plus d’une.
windowwindowrolling seulementNombre entier de périodes à inclure dans la fenêtre glissante.
functionfunctionrolling seulementFonction d’agrégation sur la fenêtre : sum (par défaut) ou avg.
formatStringformat_stringnonChaîne de format MDX appliquée au membre généré, par ex. "0.0%" ou "#,###".

Types de métrique

yoy — croissance year-over-year

Rapporte le pourcentage de changement par rapport à la même période de l’année précédente.

Forme de formule :

([Measures].[<measure>] -
(ParallelPeriod([<dim>].[<YearLevel>], 1, [<dim>].CurrentMember),
[Measures].[<measure>]))
/
(ParallelPeriod([<dim>].[<YearLevel>], 1, [<dim>].CurrentMember),
[Measures].[<measure>])

L’appel à ParallelPeriod navigue vers la même position relative un an en arrière en utilisant le niveau TimeYears. Le résultat est NULL pour la première année complète de données (aucune année précédente disponible).

pop — croissance period-over-period

Rapporte le pourcentage de changement par rapport à la période immédiatement précédente (la période juste avant la courante au même niveau).

Forme de formule :

([Measures].[<measure>] -
(PrevMember([<dim>].CurrentMember), [Measures].[<measure>]))
/
(PrevMember([<dim>].CurrentMember), [Measures].[<measure>])

PrevMember recule d’une position dans l’ordre naturel de la dimension. Les résultats sont NULL pour le tout premier membre d’un niveau (aucun prédécesseur).

ytd — cumulatif year-to-date

Rapporte la valeur cumulative de la mesure depuis le début de l’année courante jusqu’à la période courante.

Forme de formule :

Aggregate(Ytd([<dim>].CurrentMember), [Measures].[<measure>])

Ytd() renvoie l’ensemble de toutes les périodes depuis la première période de l’année courante jusqu’à la période courante. Aggregate applique l’agrégation native de la mesure (typiquement sum) sur cet ensemble.

rolling — fenêtre glissante

Rapporte l’agrégat de la mesure sur les window dernières périodes, en utilisant sum ou avg.

Forme de formule (avg, window=3) :

Avg(LastPeriods(3, [<dim>].CurrentMember), [Measures].[<measure>])

Forme de formule (sum, window=N) :

Sum(LastPeriods(N, [<dim>].CurrentMember), [Measures].[<measure>])

LastPeriods(N, member) renvoie l’ensemble des N périodes se terminant au membre courant. Si moins de N périodes sont disponibles (par ex. tôt dans l’historique des données), la fenêtre se rétrécit au nombre de périodes existantes — elle ne complète pas avec des zéros.

Comportement de validation

Le chargeur est fail-closed : le chargement du schema est interrompu avec un message d’erreur clair si l’une des conditions suivantes est détectée.

ConditionErreur
measure nomme un membre qui n’existe pas dans le cubeTimeCalc "X": measure "Y" not found in cube
Pas de timeDimension spécifié et le cube a zéro dimension TIMETimeCalc "X": cube has no TIME dimension
Pas de timeDimension spécifié et le cube a plus d’une dimension TIMETimeCalc "X": cube has multiple TIME dimensions — specify timeDimension
timeDimension nomme une dimension qui n’existe pas dans le cubeTimeCalc "X": timeDimension "Y" not found
type="rolling" et window est manquant ou n’est pas un entier positifTimeCalc "X": rolling type requires a positive integer window
type="yoy" mais aucun niveau TimeYears n’existe dans la dimensionTimeCalc "X": TIME dimension has no TimeYears level

Il n’y a pas de résultat silencieusement faux — chaque mauvaise configuration est attrapée avant que la première requête ne s’exécute.

Exemple commenté : chiffre d’affaires mensuel de la démo Bank

La démo Bank livre un cube Monthly Revenue sur une série de chiffres d’affaires mensuels. Les données brutes pour deux ans :

YearMonthRevenue
2024Jan100
2024Feb200
2024Mar300
2025Jan150
2025Feb250
2025Mar350

Le cube déclare les quatre types <TimeCalc> contre la dimension Calendar (Year > Quarter > Month) :

<TimeCalcs>
<TimeCalc name="Revenue YoY" type="yoy" measure="Revenue" timeDimension="Calendar" formatString="0.0%"/>
<TimeCalc name="Revenue PoP" type="pop" measure="Revenue" timeDimension="Calendar" formatString="0.0%"/>
<TimeCalc name="Revenue YTD" type="ytd" measure="Revenue" timeDimension="Calendar"/>
<TimeCalc name="Revenue R3" type="rolling" measure="Revenue" timeDimension="Calendar" window="3" function="avg"/>
</TimeCalcs>

Résultats de référence

CelluleValeurComment
Revenue YoY à [Calendar].[2025].[Q1].[Jan 2025]0.5 (50%)(150 − 100) / 100 = 0.5
Revenue PoP à [Calendar].[2024].[Q1].[Feb 2024]1.0 (100%)(200 − 100) / 100 = 1.0
Revenue YTD à [Calendar].[2024].[Q1].[Mar 2024]600100 + 200 + 300 = 600
Revenue R3 à [Calendar].[2025].[Q1].[Mar 2025]250avg(150, 250, 350) = 250

Exemple de requête MDX

SELECT
{ [Measures].[Revenue],
[Measures].[Revenue YoY],
[Measures].[Revenue PoP],
[Measures].[Revenue YTD],
[Measures].[Revenue R3] } ON COLUMNS,
[Calendar].[Month].Members ON ROWS
FROM [Monthly Revenue]

Résultat partiel (2024–2025 Jan à Mar) :

MonthRevenueYoYPoPYTDR3
Jan 2024100100100
Feb 2024200100.0%300150
Mar 202430050.0%600200
Jan 202515050.0%−50.0%150216.7
Feb 202525025.0%66.7%400233.3
Mar 202535016.7%40.0%750250

Les tirets (—) indiquent NULL — aucune donnée d’année précédente ou aucune période prédécesseur n’est disponible.

Relation avec <CalculatedMembers>

Les déclarations <TimeCalc> sont désucrites au moment du chargement en éléments <CalculatedMember> sur [Measures]. Les membres générés sont indiscernables des membres calculés écrits à la main au moment de la requête : ils apparaissent dans les énumérations de membres XMLA, ils répondent à FORMAT_STRING et peuvent être référencés par d’autres membres calculés.

Si vous avez besoin d’une formule que <TimeCalc> ne peut pas exprimer — par exemple, une métrique mixte personnalisée ou un ratio multi-mesures avant une comparaison temporelle — utilisez un <CalculatedMember> simple directement. Les deux approches peuvent coexister dans le même cube.

Voir Avancé — Membres calculés pour la référence complète <CalculatedMember>.