Zum Inhalt springen

Time Intelligence (deklarativ: YoY, PoP, YTD, Rolling)

Mondrian-4 unterstützt ein <TimeCalc>-Schema-Element, das gängige Time-Intelligence-Metriken deklariert. Der Schema-Loader entzuckert jede Deklaration in einen validierten <CalculatedMember> auf [Measures] – Sie sagen also was Sie möchten, statt MDX-Formeln von Hand zu schreiben und zu pflegen.

Warum deklarative Time Intelligence?

Ohne <TimeCalc> erfordert Year-over-Year-Wachstum einen berechneten Member wie:

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

Mit <TimeCalc> ist dieselbe Metrik:

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

Der Loader erzeugt das MDX für Sie, validiert, dass die referenzierte Measure und Zeitdimension existieren, und wirft einen Ladezeitfehler, statt ein still falsches Ergebnis zu produzieren.

Voraussetzung: eine getypte Time-Dimension

<TimeCalc> erfordert, dass der Cube eine getypte Time-Dimension hat – eine <Dimension> mit type="TIME", deren Hierarchie benannte Ebenen für Jahr, Quartal und Monat hat. Die Jahresebene muss levelType="TimeYears" tragen, und die Quartals- und Monatsebenen müssen levelType="TimeQuarters" bzw. levelType="TimeMonths" tragen. Die innerhalb-eines-Jahres-Berechnungen (ytd, pop, rolling) erfordern mindestens eine Monatsebene in der Hierarchie.

Eine minimale Calendar-Dimension, die die Anforderung erfüllt:

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

Platzierung im Schema

<TimeCalc>-Elemente werden in einem <TimeCalcs>-Block innerhalb eines <Cube> auf derselben Ebene wie <CalculatedMembers> eingeschlossen:

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

Attributreferenz

AttributXML / YAML-SchlüsselErforderlichBeschreibung
namenamejaDer Name des erzeugten berechneten Members. Erscheint in [Measures] wie jede andere Measure.
typetypejaDer Metriktyp: yoy, pop, ytd oder rolling. Siehe Metriktypen unten.
measuremeasurejaDer Name einer existierenden <Measure> im Cube. Der Loader lehnt eine unbekannte Measure beim Schema-Load ab.
timeDimensiontime_dimensionbedingtDer Name einer type="TIME"-Dimension. Kann weggelassen werden, wenn der Cube genau eine TIME-Dimension hat; erforderlich, wenn er mehr als eine hat.
windowwindownur rollingGanzzahlige Anzahl der Perioden, die in das rollende Fenster einbezogen werden.
functionfunctionnur rollingAggregationsfunktion über das Fenster: sum (Standard) oder avg.
formatStringformat_stringneinMDX-Format-String, der auf den erzeugten Member angewendet wird, z. B. "0.0%" oder "#,###".

Metriktypen

yoy – Year-over-Year-Wachstum

Berichtet die prozentuale Änderung im Vergleich zur gleichen Periode im Vorjahr.

Formelform:

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

Der ParallelPeriod-Aufruf navigiert mit der TimeYears-Ebene zur gleichen relativen Position ein Jahr zurück. Das Ergebnis ist NULL für das erste volle Datenjahr (kein Vorjahr verfügbar).

pop – Period-over-Period-Wachstum

Berichtet die prozentuale Änderung im Vergleich zur unmittelbar vorhergehenden Periode (die Periode direkt vor der aktuellen auf derselben Ebene).

Formelform:

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

PrevMember geht eine Position in der natürlichen Ordnung der Dimension zurück. Ergebnisse sind NULL für den allerersten Member einer Ebene (kein Vorgänger).

ytd – Year-to-Date kumulativ

Berichtet den kumulierten Wert der Measure vom Anfang des aktuellen Jahres bis zur aktuellen Periode.

Formelform:

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

Ytd() gibt die Menge aller Perioden von der ersten Periode des aktuellen Jahres bis zur aktuellen Periode zurück. Aggregate wendet die native Aggregation der Measure (typischerweise sum) über diese Menge an.

rolling – Rolling Window

Berichtet das Aggregat der Measure über die letzten window Perioden, unter Verwendung von sum oder avg.

Formelform (avg, window=3):

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

Formelform (sum, window=N):

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

LastPeriods(N, member) gibt die Menge der N Perioden zurück, die am aktuellen Member enden. Wenn weniger als N Perioden verfügbar sind (z. B. früh in der Datenhistorie), schrumpft das Fenster auf die Anzahl tatsächlich existierender Perioden – es wird nicht mit Nullen aufgefüllt.

Validierungsverhalten

Der Loader ist fail-closed: Das Laden des Schemas wird mit einer klaren Fehlermeldung abgebrochen, wenn eine der folgenden Bedingungen erkannt wird.

BedingungFehler
measure benennt einen Member, der nicht im Cube existiertTimeCalc "X": measure "Y" not found in cube
Keine timeDimension angegeben und der Cube hat null TIME-DimensionenTimeCalc "X": cube has no TIME dimension
Keine timeDimension angegeben und der Cube hat mehr als eine TIME-DimensionTimeCalc "X": cube has multiple TIME dimensions — specify timeDimension
timeDimension benennt eine Dimension, die nicht im Cube existiertTimeCalc "X": timeDimension "Y" not found
type="rolling" und window fehlt oder ist keine positive GanzzahlTimeCalc "X": rolling type requires a positive integer window
type="yoy", aber keine TimeYears-Ebene existiert in der DimensionTimeCalc "X": TIME dimension has no TimeYears level

Es gibt kein still falsches Ergebnis – jede Fehlkonfiguration wird vor der ersten Abfrage erkannt.

Beispiel: Monatlicher Umsatz aus der Bank-Demo

Die Bank-Demo liefert einen Monthly Revenue-Cube über eine monatliche Umsatzreihe. Die Rohdaten für zwei Jahre:

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

Der Cube deklariert alle vier <TimeCalc>-Typen gegen die Calendar-Dimension (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>

Erwartete Ergebnisse

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

Beispiel-MDX-Abfrage

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]

Teilergebnis (2024–2025, Januar bis März):

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

Bindestriche (—) zeigen NULL an – keine Vorjahresdaten oder keine Vorgängerperiode verfügbar.

Beziehung zu <CalculatedMembers>

<TimeCalc>-Deklarationen werden zur Ladezeit zu <CalculatedMember>-Elementen auf [Measures] entzuckert. Die erzeugten Members sind zur Abfragezeit von handgeschriebenen berechneten Members nicht zu unterscheiden: Sie erscheinen in XMLA-Member-Enumerationen, reagieren auf FORMAT_STRING und können von anderen berechneten Members referenziert werden.

Wenn Sie eine Formel benötigen, die <TimeCalc> nicht ausdrücken kann – z. B. eine benutzerdefinierte gemischte Metrik oder ein Multi-Measure-Verhältnis vor einem Zeitvergleich – verwenden Sie direkt einen einfachen <CalculatedMember>. Beide Ansätze können im selben Cube koexistieren.

Siehe Fortgeschritten – Berechnete Members für die vollständige <CalculatedMember>-Referenz.