CiAgICA8IS0tIExpbmtlZEluIC0tPgogICAgPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPgogICAgICAgIF9saW5rZWRpbl9wYXJ0bmVyX2lkID0gIjEyMzUwNzMiOwogICAgICAgIHdpbmRvdy5fbGlua2VkaW5fZGF0YV9wYXJ0bmVyX2lkcyA9IHdpbmRvdy5fbGlua2VkaW5fZGF0YV9wYXJ0bmVyX2lkcyB8fCBbXTsKICAgICAgICB3aW5kb3cuX2xpbmtlZGluX2RhdGFfcGFydG5lcl9pZHMucHVzaChfbGlua2VkaW5fcGFydG5lcl9pZCk7CiAgICA8L3NjcmlwdD48c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+CiAgICAgICAgKGZ1bmN0aW9uKCl7dmFyIHMgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgic2NyaXB0IilbMF07CiAgICAgICAgICAgIHZhciBiID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7CiAgICAgICAgICAgIGIudHlwZSA9ICJ0ZXh0L2phdmFzY3JpcHQiO2IuYXN5bmMgPSB0cnVlOwogICAgICAgICAgICBiLnNyYyA9ICJodHRwczovL3NuYXAubGljZG4uY29tL2xpLmxtcy1hbmFseXRpY3MvaW5zaWdodC5taW4uanMiOwogICAgICAgICAgICBzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGIsIHMpO30pKCk7CiAgICA8L3NjcmlwdD4KICAgIDxub3NjcmlwdD4KICAgICAgICA8aW1nIGhlaWdodD0iMSIgd2lkdGg9IjEiIHN0eWxlPSJkaXNwbGF5Om5vbmU7IiBhbHQ9IiIgc3JjPSJodHRwczovL3B4LmFkcy5saW5rZWRpbi5jb20vY29sbGVjdC8/cGlkPTEyMzUwNzMmZm10PWdpZiIgLz4KICAgIDwvbm9zY3JpcHQ+CiAgICA8IS0tIEVuZCBMaW5rZWRJbiAtLT4KICAgIA==
Generic filters
Exact matches only
Search in title
Search in excerpt
Search in content

Vorjahresvergleich im Schaltjahr

Dieses Jahr ist es wieder soweit. Wir haben ein Schaltjahr. An sich ist das nicht schlimm, unsere Tagesperioden wurden robust eingefügt, die OLAP-Datenbank ist aufbereitet und dann das: Der Vorjahresvergleich liefert am 29.02.2012 kein Ergebnis. Auswege werden im heutigen Blogbeitrag gezeigt.

Vorbetrachtung

Das beschriebene Verhalten tritt auch regelmäßig bei Geschäftsjahresbetrachtungen auf, wenn ein Rumpfgeschäftsjahr abgebildet werden musste.

Die für den Vorjahresvergleich regelmäßig eingesetzte MDX-Funktion ParallelPeriod() gibt die gleiche Periode im letzten Jahr zurück. Also ergibt sich für den 03.02.2012 bei “normalem” Aufbau der Periodendimension der 03.02.2011 als Element für den Vorjahresvergleich. Beim 29.02.2012 wird aber NULL zurückgegeben, da es im Vorjahr kein 29. Tageselement im Monat Februar gab.

Im kommenden Jahr kann der Vorjahresvergleich mit kumulierten Zahlen sogar scheinbar falsche Werte produzieren, da am Monatsletzten (28.02.2013) mit einem Tag “mitten” aus dem Monat verglichen wird und damit die aufgelaufenen Monatswerte auf Tagesbasis und Monatsbasis für das Vorjahr scheinbar nicht zusammen passen. Wie gehen wir mit diesem Verhalten um? MDX hat für solche Sonderfälle leider nichts übrig.

Die Assistenten in DeltaMaster unterstützen den Anwender durch die Generierung von intelligenten MDX-Statements. Leider wird dieser Sonderfall im Assistenten auch nicht behandelt.

Bei genauer Betrachtung sind zwei Fragen zu klären:

  1. a) Was soll passieren, wenn ich den 29.02.2012 mit dem Vorjahr vergleiche?
  2. b) Was soll im kommenden Jahr passieren – da gibt es keinen 29.02. (mehr)?

Die erste Frage wird sicher meist damit beantwortet, dass man den Monatsletzten für den Vorjahresvergleich auswählen will. So wird eine Monatsverschiebung vermieden und man bekommt auch kumuliert schlüssige Werte.

Die zweite Frage ist im Projekt zu diskutieren. Eine mögliche Idee ist das Ausweichen auf den Monatswert bei kumulierter Betrachtung. Für den einzelnen Tageswert wage ich hier keine Prognose…

Nachfolgend sollen einige Ansätze für die Lösung der Frage a) dargelegt werden.

Der Vorjahresvergleich am 29.02.2012

Für den Vorjahresvergleich legt der Assistent zur Anlage eines Zeitanalyseelementes in DeltaMaster ein Statement sehr ähnlich diesem hier ab:

(
ParallelPeriod([Periode].[Periode].[Jahr], 1, [Periode].[Periode].CurrentMember),
[Periodenansicht].[Periodenansicht].[Periodenansicht].&[1]
)

Wir müssen dieses Statement um eine Fallunterscheidung erweitern. Je nach Festlegung im Projekt muss auf den nächsten oder den vorherigen Tag verwiesen werden. Da die Monatsgrenze nicht gebrochen wird, legen wir uns hier im Beispiel auf den vorherigen Tag fest. Das Statement soll natürlich auch künftige und zurückliegende Schaltjahre abbilden können.

Für das gewählte Beispiel ergibt sich folgendes Statement:

(
iif(left([Periode].[Periode].currentmember.name,6)="29.02.",
    ParallelPeriod([Periode].[Periode].[Jahr], 1, [Periode].[Periode].CurrentMember.lag(1)),
    ParallelPeriod([Periode].[Periode].[Jahr], 1, [Periode].[Periode].CurrentMember)
    ),
[Periodenansicht].[Periodenansicht].[Periodenansicht].&[1]
)

Nur für den 29.02. soll mit Hilfe der Fallunterscheidung auf den Vortag (28.02.) ausgewichen werden.

Auch bei der Bezeichnung kann man leider nicht auf den bekannten Standard ({pya1,1}) zurückgreifen, da er letztlich am eingangs genannten Problem scheitert. Für die Bezeichnung verwenden wir

{
iif(left([Periode].[Periode].currentmember.name,6)="29.02.",
    ParallelPeriod([Periode].[Periode].[Jahr], 1, [Periode].[Periode].CurrentMember.lag(1)).name,
    ParallelPeriod([Periode].[Periode].[Jahr], 1, [Periode].[Periode].CurrentMember).name
)
}

DeltaMaster erwartet das Statement einzeilig (Stand V 5.5.0). Es wurde wegen besserer Lesbarkeit um ein paar Zeilenumbrüche und Leerzeichen erweitert.

Erweiterung des Ansatzes für ein Rumpfgeschäftsjahr

Soll der Vergleich zu einem Rumpfgeschäftsjahr erfolgen, ergeben sich neue Herausforderungen. Es geht in diesem Fall nicht allein darum, einen einzelnen Tag “abzufangen”, sondern alle Folgeperioden. Befindet man sich im Vorjahresvergleich außerhalb des Rumpfgeschäftsjahres, wird die letzte Periode des Rumpfgeschäftsjahres ausgewählt sonst wie gewohnt die zugehörige Vorjahresperiode.

Ein möglicher Ansatz kann das Zählen und Vergleichen der Perioden des Geschäftsjahres sein.

iif(count(
        descendants(    ancestor(   [Periode].[Periode].CurrentMember,
                                    [Periode].[Periode].[Jahr]),
                        [Periode].[Periode].CurrentMember.level
            ).item(0):[Periode].[Periode].CurrentMember
        )

    <=
    count(
        descendants(    ancestor(   [Periode].[Periode].CurrentMember,
                                    [Periode].[Periode].[Jahr]).lag(1),
                        [Periode].[Periode].CurrentMember.level
            )
        ),

    ParallelPeriod([Periode].[Periode].[Jahr], 1, [Periode].[Periode].CurrentMember),
    tail(descendants(   ancestor(   [Periode].[Periode].CurrentMember,
                                    [Periode].[Periode].[Jahr]),
                        [Periode].[Periode].CurrentMember.level
                )
        ).item(0)
    ),
[Periodenansicht].[Periodenansicht].[Periodenansicht].&[1]
)

Auch hier ist wieder auf eine sprechende Elementbezeichnung zu achten, so dass der Anwender immer über die genaue Vergleichsperiode informiert ist.