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

Optimierung von MDX - direkte Zuweisung statt scope

Oft ist es nötig, Berechnungen für Kennzahlen bereits im Cube-Skript vorzunehmen. Insbesondere wenn die relationale Datenquelle nur eine oder wenige Kennzahlen enthält, die mit Struktur-Dimensionen geschnitten werden müssen, kommt man um die Erstellung von Kennzahlen im Cube-Skript nicht herum. Komplex wird es, wenn zusätzlich eine Bestands-Kumulation oder andere Berechnungen hinzukommen. Bei der Erstellung von Scope-Definitionen muss man auf physisch gelieferte Kennzahlen zurückgreifen können, um im Scope eine Menge von Kennzahlen bereits in einer Definition zu manipulieren. Für Kennzahlen, die im Cube-Skript definiert werden, muss man diese Definitionen einzeln wiederholen, da eine Zusammenfassung nicht möglich ist. Hierfür gibt es aber eine alternative Möglichkeit, die in diesem Blogbeitrag genauer erläutert wird.

Kennzahlen-Dimension

Im vorliegenden Beispiel werden Längenangaben von Produkten in Zentimetern geliefert, sollen aber als Meter weiterverarbeitet werden. Außerdem sollen die Längenangaben in der Artikel-Dimension in übergeordneten Ebenen nicht summiert, sondern gemittelt werden. Die Werte werden in einer einfachen Tabelle mit einer Wert-Spalte geliefert. Die Interpretation des Wertes findet über eine Verbindung mit der ebenfalls gelieferten Kennzahl_ID statt und muss einmalig im Cube-Skript hergestellt werden. Alternativ kann man per SQL-Skript die Faktentabelle um Spalten für jede Kennzahl erweitern. In manchen Modellen kann es aber einfacher sein, nur eine Anpassung am Cube-Skript vorzunehmen, wenn neue Kennzahlen geliefert werden. Ein Anpassen des Datenmodells über den
DeltaMaster Modeler ist dann nicht nötig. Quelltabellen der Dimension und Fakten:
Dimension „Kennzahlen“:

Dimension „Artikel“:

Faktendaten:

Aus den gelieferten Dimensionen und der Kennzahl „Wert“ werden im Cube-Skript entsprechende Kennzahlen erstellt:


CREATE MEMBER CURRENTCUBE.[Measures].[Herstellungskosten]
 AS ([Measures].[Wert],[Kennzahl].[Kennzahl].[Kennzahl].&[1]) 
 , VISIBLE = 1
 , ASSOCIATED_MEASURE_GROUP = 'Artikelwerte' 
;

CREATE MEMBER CURRENTCUBE.[Measures].[Verkaufspreis]
 AS ([Measures].[Wert],[Kennzahl].[Kennzahl].[Kennzahl].&[2]) 
 , VISIBLE = 1
 , ASSOCIATED_MEASURE_GROUP = 'Artikelwerte' 
;

CREATE MEMBER CURRENTCUBE.[Measures].[Anzahl]
 AS ([Measures].[Wert],[Kennzahl].[Kennzahl].[Kennzahl].&[3]) 
 , VISIBLE = 1
 , ASSOCIATED_MEASURE_GROUP = 'Artikelwerte' 
;

CREATE MEMBER CURRENTCUBE.[Measures].[Höhe]
 AS ([Measures].[Wert],[Kennzahl].[Kennzahl].[Kennzahl].&[4]) 
 , VISIBLE = 1
 , ASSOCIATED_MEASURE_GROUP = 'Artikelwerte' 
;

CREATE MEMBER CURRENTCUBE.[Measures].[Länge]
 AS ([Measures].[Wert],[Kennzahl].[Kennzahl].[Kennzahl].&[5]) 
 , VISIBLE = 1
 , ASSOCIATED_MEASURE_GROUP = 'Artikelwerte' 
;

CREATE MEMBER CURRENTCUBE.[Measures].[Breite]
 AS ([Measures].[Wert],[Kennzahl].[Kennzahl].[Kennzahl].&[6]) 
 , VISIBLE = 1
 , ASSOCIATED_MEASURE_GROUP = 'Artikelwerte' 
;

.
.
.

Fehler bei Scope-Berechnung für Durchschnittswerte

Versucht man nun per Scope-Anweisung für mehrere Kennzahlen eine Berechnung durchzuführen, schlägt dies fehl:

Beispiel:


scope
(
{[Measures].[Breite],
[Measures].[Gewicht],
[Measures].[Höhe],
[Measures].[Länge]}
,[Artikel].[Artikel].[Alle Artikel]
);
THIS = AVG(descendants([Artikel].[Artikel].CurrentMember,[Artikel].[Artikel].[Artikel]));
end scope;

 

Abbildung 1: Fehlermeldung

Zur Auflösung des Fehlers müsste man nun gemäß Hinweis für jede Kennzahl eine einzelne Scope-Anweisung erstellen. Dies führt zu einem unnötigen Aufblähen des Skripts und einer erschwerten Wartbarkeit. Beispielsweise soll für mehrere Kennzahlen eine Bestandslogik in der Kumulations-Dimension realisiert werden, bei der die Berechnung für alle Kennzahlen identisch ist.

Lösung über eine direkte Anweisung

Um diesen Scope nun nicht in einzelne Anweisungen für jede berechnete Kennzahl vervielfachen zu müssen, gibt es eine alternative Möglichkeit:


(
{[Measures].[Breite],
[Measures].[Gewicht],
[Measures].[Höhe],
[Measures].[Länge]}
,[Artikel].[Artikel].[Alle Artikel]
)
= AVG(descendants([Artikel].[Artikel].CurrentMember,[Artikel].[Artikel].[Artikel]));

Statt einer „Scope-Klammer“ erfolgt die Zuweisung direkt. Das Ergebnis ist identisch zum Scope.
Beispiel für die Umrechnung von Zentimeter in Meter:


({[Measures].[Breite],
[Measures].[Höhe],
[Measures].[Länge]}
) 
= [Measures].CurrentMember / 100;

Fazit

Ein generischer Ansatz zur Definition eines Kennzahlenmodells lässt sich mit Hilfe der direkten Zuweisungen auch ohne Scope-Definitionen komfortabel und schlank per Cube-Skript realisieren.