Vor einigen Wochen erschien der Blogbeitrag „Finde den Tag. Dort wird über die Tücken berichtet, die uns ein Kalender bei tagesgenauen Vorjahresvergleichen bescheren kann. Ein ähnliches Thema hat uns auch in einem anderen Projekt getroffen. Es ging um den Aufbau eines Monatsberichts, der tagesaktuell, d. h. zum aktuellen Stand im Monat, die kumulierte Abweichung eines Standorts gegenüber dem Vormonat darstellen sollte. Hört sich trivial an, ist es aber nicht. Denn auch hier schlägt der zeitliche Vergleich des aktuellen Tages mit dem entsprechenden Tag des Vormonats fehl, da mitunter Werktage mit Wochenenden oder Feiertagen verglichen werden. Nur die Berücksichtigung der Anzahl an Arbeitstagen ermöglicht einen aus betriebswirtschaftlicher Sicht korrekten Vergleich der Geschäftsentwicklung zum jeweiligen Stand im Vormonat. Wie der Bericht letztlich gestaltet wurde, welche Voraussetzungen im Modell gegeben sein müssen und welches MDX benötigt wird, um die Abweichung auf Basis normierter Arbeitstage zu berechnen, beschreibt dieser Blogbeitrag.
Voraussetzungen im Datenmodell
Es gibt verschiedene Modellierungsansätze, um einen Arbeitstag in einer Periodendimension, die entsprechend dem gregorianischen Kalender aufgebaut ist, zu identifizieren. Am einfachsten scheint es, Arbeitstage direkt in der Periodendimension durch ein hierfür eingerichtetes Attributfeld zu kennzeichnen. Der Attributwert „1“ repräsentiert einen Arbeitstag. Alternativ könnte auch eine Measuregroup ins OLAP-Modell integriert werden, die ausschließlich der Kennzeichnung von Arbeitstagen dient. In Verbindung mit dem Tagesdatum hätte deren Analysewert „Arbeitstag“ ebenfalls den Wert „1“, wenn es sich um einen Arbeitstag handelt. Anders als bei einem Attribut, bei dem Arbeitstage stets unabhängig von regionalen Gegebenheiten und somit für alle Organisationseinheiten identisch wären, könnte ein Analysewert die Arbeitstage je Standort unterschiedlich ausweisen. Somit würde man regionalen Besonderheiten, wie beispielsweise unterschiedlichen Feiertagen in den Bundesländern, Rechnung tragen. Voraussetzung wäre lediglich, dass die Measuregroup mit dem Arbeitstag-Flag neben der Periodendimension auch die Organisationsstruktur beinhaltet. Auf diese Weise erreicht man Genauigkeit je Standort. Bei einer Betrachtung des gesamten Unternehmens wird man jedoch einen Kompromiss eingehen müssen. Spätestens hier müssten die Arbeitstage wieder für alle Standorte aus allen Regionen einheitlich festgelegt werden.
Im betreffenden Projekt entschieden wir uns für den einfachen Weg, nämlich zur Nutzung eines Attributes in der Periodendimension. Dieser Ansatz wird im Folgenden weiter ausgeführt.
Normierung der Arbeitstage
Anhand des Arbeitstag-Attributs lässt sich für einen ausgewählten Monat () eine Liste aller Arbeitstage erzeugen. Hierzu benötigt man ein kleines MDX-Statement, das mittels FILTER-Funktion nur diejenigen Tage auswählt, die den Attributwert „1“ haben:
Filter( {Descendants(, [Periode].[Periode].[Tag])}, [Periode].[Periode].CurrentMember.Properties("Arbeitstag",TYPED)=1 )
In dieser Liste, die man im DeltaMaster idealerweise als NamedSet „[NameSet AT ]“ speichert, können wir nun die Arbeitstage zählen und ihre Position eindeutig bestimmen. Das genaue Tagedatum spielt nämlich ab sofort keine Rolle mehr. Der 02.10.2013 ist für unsere Betrachtung der zweite Arbeitstag im Oktober (da der 01.10.2013 ein Dienstag ist). Die Position entspricht somit der Arbeitstag-ID. Diese lässt sich durch folgendes MDX ermitteln:
RANK( [Periode].[Periode].CurrentMember, [NamedSet AT ] )
Auf Basis der Berechnung einer Arbeitstag-ID lässt sich leicht der entsprechende Tag des Vormonats ausfindig machen. Hierzu muss derjenige Tag gesucht werden, der die identische Position in der Liste der Arbeitstage des Vormonats wie der gerade betrachtete Tag des aktuellen Monats hat. Im Fall des 02.10.2013, dem zweiten Arbeitstag im Oktober, wäre der 03.09.2013 der zu vergleichende Arbeitstag des Vormonats, da der 01.09.2013 ein Sonntag ist. Um den Vormonatstag zu identifizieren benötigen wir eine Liste mit den Arbeitstagen des Vormonats, die sich wie oben unter Verwendung der LAG()-Funktion erzeugen und als NamedSet „[NamedSet AT ]“ speichern lässt:
Filter( {Descendants(.lag(1), [Periode].[Periode].[Tag])}, [Periode].[Periode].CurrentMember.Properties("Arbeitstag",TYPED)=1 )
Mittels der ITEM()-Funktionen und der Angabe der Position lässt sich in der Liste von Arbeitstagen des Vormonats der vergleichbare Tag ermitteln. Hierbei muss lediglich beachtet werden, dass der Index der ITEM()-Funktion 0-basiert ist. Der erste Arbeitstag in der Liste entspricht Item(0). Daher muss vom Rang des aktuellen betrachteten Arbeitstages der Wert 1 abgezogen werden:
[NamedSet AT ].item( RANK( [Periode].[Periode].CurrentMember, [NamedSet AT ] ) )-1
Vorperiodenabweichung auf Basis der Arbeitstage
Grundsätzlich kann die Abweichung des aktuell betrachteten Tages vom jeweiligen Arbeitstag des Vormonats mit einem berechneten Element in der Dimension Periodenansicht als „∆VP (AT)“ ermittelt werden. Eine Nebenbedingung gilt es jedoch noch zu berücksichtigen. Wie verfahren wir, wenn der laufende Monat weniger oder mehr Arbeitstage als der Vormonat hat? Muss die Berechnung angepasst werden? Bedarf es eines speziellen Berichtslayouts? Hierzu rufen wir uns nochmals die Ausgangssituation in Erinnerung, nämlich die Darstellung und Analyse der Geschäftsentwicklung gegenüber dem Vormonat auf Basis von Arbeitstagen. Selbstverständlich hat die Anzahl an Arbeitstagen einen entscheidenden Einfluss auf das absolute Monatsergebnis. In Monaten mit mehr Arbeitstagen würde man in aller Regel auch ein proportional höheres Ergebnis als in Monaten mit vergleichsweise weniger Tagen erwarten. Folglich muss auf diese Effekte hingewiesen werden. Worauf es letztlich ankommt, ist die Darstellung des laufenden Monats mit Blick auf den Vormonat, und nicht umgekehrt.
Sollte der laufende Monat also mehr Arbeitstage als der Vormonat aufweisen, so würden wir die zusätzlichen Arbeitstage anzeigen und bei kumulierter Betrachtung für eben diese Tage stets auf den letzten Arbeitstag des Vormonats referenzieren. Das MDX-Statement zur Berechnung der Vorperiodenabweichung müsste für diesen Fall angepasst werden. Hierzu prüfen wir mit Hilfe von IIF- und COUNT-Funktionen, ob der aktuelle Monat mehr Arbeitstage als der Vormonat hat und ob die Werte kumuliert betrachtet werden:
[Periode].[Periode].CurrentMember - [NamedSet AT ].item( -- ermittle die ID der Vergleichsperiode iif( RANK( [Periode].[Periode].CurrentMember, [NamedSet AT ]) <= [NamedSet AT ].count , -- wenn aktuelle AT-ID im Vormonat existiert, dann diese ID RANK( [Periode].[Periode].CurrentMember, [NamedSet AT ] )-1 , -- sonst, wenn aktuelle AT-ID im Vormonat nicht existiert -- und kum. Betrachtung iif( [Kumulation].[Kumulation].CurrentMember is “kumuliert” , -- dann ID des letzten AT des Vormonats wählen [NamedSet AT ].count-1 , -- oder Null bei nicht kum. Betrachtung anzeigen, weil AT nicht -- existiert NULL ) -- end iif ) -- end iif ) -- Item
Sollte der aktuelle Monat weniger Arbeitstage als der Vormonat haben, so würden wir die zusätzlichen Arbeitstage des Vormonats nicht explizit anzeigen. Auch hinsichtlich der Berechnung der kumulierten Abweichung müssten keine zusätzlichen Vorkehrungen getroffen werden. Dennoch sollte aus Gründen der Vollständigkeit der gesamte Vormonatswert und die Gesamtabweichung als zusätzliche Information im Bericht aufgeführt werden.
Abschließend bedarf es auch noch der Erwähnung der Anzahl an Arbeitstagen beider Monate mit Ausweis der Differenz. Dies lässt sich ebenfalls gut in der Tabelle oder der Berichtsüberschrift durch die Abfrage entsprechender Analysewerte bewerkstelligen.
Berichtslayout
Der Monatsbericht sollte sich an den Regeln der Stilfibel orientieren. Zeit läuft von links nach rechts: die Anzeige der Monatssummen und der Arbeitstage des laufenden Monats ([NamedSet AT ]) erfolgt daher in der Spaltenachse des Berichts. Kennzahlen und Periodenansicht (∆VP (AT), aktuell) werden in den Zeilen angezeigt. Sofern dies noch nicht in der Spaltenüberschrift verankert ist, könnte die Arbeitstag-ID als weitere Kennzahl in der Zeilenachse angezeigt werden. Fokus des Berichts ist die nicht-kumulierte oder kumulierte Entwicklung der Abweichung. Folglich aktivieren wir die Säulengrafik der Pivottabelle bei den Zeilen, die die Vorperiodenabweichung auf Basis der Arbeitstage beinhalten. Das Ergebnis am Beispiel für August und September 2012 sieht wie folgt aus (Arbeitstage 13 bis 19 sind ausgeblendet, Werte kumuliert):
Um die Berechnung nachzuvollziehen, wird in obigem Screenshot noch der Vorperiodenwert (VP AT) angezeigt. Im fertigen Bericht existiert diese Zeile nicht mehr. Zu jedem Datum wird die Arbeitstag-ID angezeigt, auf deren Basis der Vormonatswert und die Vormonatsabweichung berechnet werden. Der 03.09.2012 war der erste Arbeitstag im September. Sein Vergleichstag ist Mittwoch, der 01.08.2012. Offensichtlich war der 03.09.2012 ein Montag. Ihm folgen vier weitere Tage ohne Datumssprung. Ab dem dritten Arbeitstag war der Umsatz stets höher als zum vergleichbaren Stand im Vormonat. Und obwohl der August 2012 mit 23 Arbeitstagen ganze 3 Tage mehr als der September hatte, konnte mit einem Umsatz von 1.636TEUR ein Plus von 177TEUR erzielt werden. Nach dem 20. Arbeitstag lag man im direkten Vergleich sogar um 703TEUR über dem Vormonat. Es war ein hervorragender September 2012, was sich im Tagesvergleich bereits frühzeitig angekündigt hat. Alles dies zeigt der Bericht auf anschauliche Art und Weise. Schön – und das findet auch der Kunde.