Suchen...
Generic filters
Exact matches only
Search in title
Search in excerpt
Search in content

Die LastNonEmpty-Aggregation

In verschiedenen Beiträgen unseres Crew-Blogs haben wir uns bereits mit Beständen und der Abbildung derselben unter verschiedenen Blickwinkeln beschäftigt (vgl. Bestandsbetrachtungen, Historische Betrachtung von BestandswertenFortschreibung nichtadditiver Planwerte).

Microsoft unterstützt den Modellierer in seinen Enterprise-Varianten des SQL-Server 2005/2008 mit semi-additiven Aggregationen – LastNonEmpty oder LastChild. Diese semi-additiven Aggregationen verhalten sich auf allen “normalen” Dimensionen additiv. Also aggregieren die Analysis Services immer noch die Kunden zu Kundengruppen und die Produkte zu Produktgruppen – mit einer Ausnahme: der Zeitdimension.

Hier wird durch den Aggregationstypen festgelegt, welcher Wert in der Zeit nach oben gegeben wird.

Abgrenzung LastChild – LastNonEmpty

Lastchild gibt den Wert des letzten Kindelementes an das verdichtete Zeit-Element weiter.

LastNonEmpty sucht sich dagegen den letzten gefüllten Wert und reicht ihn an die Verdichtung weiter. Mit LastNonEmpty muss man also nicht den letzten Tag des Monats abwarten, um seine Monatsbestände analysieren zu können.

Allerdings werden Aggregate mit LastNonEmpty vergleichsweise langsam berechnet. Dies ist prinzipbedingt, da das System immer erst das letzte Element mit einem Wert suchen muss, bevor das Aggregat berechnet werden kann.

Wie LastNonEmpty wirklich arbeitet

An einem kleinen Beispiel soll nun die Wirkungsweise der LastNonEmpty-Aggregation gezeigt werden. Es wird ein (sehr kleiner) Ausschnitt einer Bestandsbetrachtung in einem Unternehmen gezeigt. Wir haben Produkte, die sich im Versandlager befinden. Unser BI-System erhält bei jeder Bestandsänderung einen neuen Bestandswert. Importiert und verarbeitet ergibt dies das folgende Bild:

Es ist zu sehen, dass sich die Kennzahl Bestand (mit Aggregation LastNonEmpty) in der Produktdimension summarisch verhält.

Nimmt man weitere Tage hinzu (z.B. eine Auswertung über alle Tage eines Quartals), ist gut zu erkennen, dass die Daten nicht an jedem Tag vollständig geliefert werden. Die Summe über alle Produkte ist aber für jeden Tag in sich schlüssig und nachvollziehbar.

Sehr häufig werden diese Bestände in aggregierter Form abgefragt. Welche Ergebnisse erwarten wir auf Monaten und Quartalen? Wir erwarten jeweils die Summe der Produkte als Monatswert und auch als Quartalswert für das Element alle Produkte. Die Summen lassen sich mit DeltaMaster über die Zeilen-/Spaltenaggregationen mit wenigen Mausklicks darstellen.

Nutzt man die Aggregation über Hierarchieebenen ergibt sich folgendes Bild:

Die Werte für Q1/2010 sowie die Januar- und Märzwerte erscheinen schlüssig. Die Summe der Produktwerte ergibt den Wert für das Element alle Produkte.

Stutzig macht der Wert für den Februar: 12x Produkt A und 13x Produkt B soll 12 ergeben.

Um dem Thema auf den Grund zu gehen schalten wir ein Quartal weiter. Hier erscheinen alle Werte irgendwie komisch und ohne tieferen Sinn zusammengestellt, aber keinesfalls aggregiert…

Wir recherchieren das Verhalten der LastNonEmpty-Aggregation:

LastNonEmpty ist wörtlich zu nehmen!

Es wird für jede Hierarchieebene in jeder Dimension der letzte nicht leere Wert zurückgegeben, sobald man sich in der Zeit nicht mehr auf der Basisebene befindet (im Beispiel sobald man nicht mehr auf Tagen auswertet).

Somit ergibt sich auf Ebene der Produkte als Quartalswert für Produkt A der Tageswert vom 30.6.2010 und für die Produkte B und C der jeweilige Tageswert vom 26.5.2010. Für alle Produkte ist der letzte nicht leere Tag allerdings der 30.6.2010. Somit wird dieser Wert für alle Produkte ausgegeben. Rechnet man die (horizontale) Summe nach, müssten sich aber 65 ergeben.

Lösungsansätze

  • Scoping

Leider ist die Berechnungslogik einer LastNonEmpty-Measure nicht beeinflussbar.

Ein Lösungsansatz mittels Scoping wäre, sich eine weitere Measure anzulegen, für welche man den Aggregationstyp Sum einstellt.

Scope(
[Produkte].[Produkte].[Produkt].Members,
{[Measures].[Bestand mit Scope]}
);
this=([Measures].[Bestand],[Kumulation].[Kumulation].[Jahr kum.])
;

Dann kann man die Summierung der Produkte mit Hilfe eines einzigen Scopes auf die neue Kennzahl Bestand mit Scope übertragen und erhält schlüssige Ergebnisse.

Natürlich bedingt die Kumulation ein Auffüllen der Bestände bis zum Jahresende. Die Kumulation wirkt sich außerdem noch einmal negativ auf die Performance des Systems aus.

  • Bestandssnapshot

Wenn es das Vorsystem ermöglicht, wäre die Übertragung des kompletten Bestandes für den Berichtstag natürlich die optimale Lösung. In diesem Fall würde die LastNonEmpty-Logik wie in unserem Beispiel im Januar 2010 sauber greifen. Wir hätten nur noch die Performance-Gesichtspunkte zu beachten. Um die Datenmengen nicht ausufern zu lassen, sei nochmals auf die Ideen aus dem Beitrag historische Betrachtung von Bestandswerten verwiesen.

  • Wertevortrag

Sollte es diese Möglichkeit nicht geben, kann man darüber nachdenken, die zugrundeliegenden relationalen Daten auf den letzten vorhandenen Periodenwert vorzutragen. Somit baut man sich den Bestandssnapshot quasi selbst auf.

Fazit

Alle drei beleuchteten Ansätze haben Vor- aber auch Nachteile. Im Rahmen der Modellierung sind diese Vor- und Nachteile immer wieder gegeneinander abzuwägen. Eine pauschal beste Lösung gibt es für dieses Dilemma leider nicht.