...oder warum sich die Ergebnisse von SUM() und CALCULATE( SUM() ) in einer berechneten Spalte unterscheiden.

Testdaten

Als Testdaten habe ich zwei Tabellen angelegt: Order und OrderLine. Die Tabellen sind 1:n miteinander verknüpft: image Die Tabelle Order ignorieren wir für den Moment. Die Tabelle OrderLine hat folgende Daten: image

SUM Zeilenkontext

In eine berechneten Spalte Gesamtwert nutzen wir die DAX-Funktion SUM (Sie können auch SUMX verwenden – das macht keinen Unterschied):

Dann erhalten wir folgende Ergebnis: image SUM summiert einfach die Werte der gesamten Tabellenzeile. Daher ist das Ergebnis in jeder Zeile identisch.

Filter und Zeilenkontext

In einer Zeile dürfen wir auf Werte der Spalten der gleiche  Zeile zugreifen. In DAX spricht man vom sogenannten Zeilenkontext. Dieser spielt bei SUM aber keine Rolle. Legen wir eine Measure an (berechnetes Feld) mit der gleichen Formel:

Wenn Sie Excel verwenden sehen Sie im Datenmodell gleich das Ergebnis: 83. Hier wundern Sie sich  nicht. Es ist ja kein Filter eingestellt. Wenn wir jetzt eine Pivot-Tabelle erstellen und beispielsweise die OrderID als Dimension verwenden, erhalten wir: image Das Measure Gesamt Measure wird viermal ausgewertet: einmal pro OrderID und einmal für die Zeile Total. SUM zählt alle Zeilen zusammen, die im aktuellen FILTER-KONTEXT zur Verfügung stehen. Durch die OrderID stehen SUM in jeder Pivot-Zeile nur die Zeilen der Tabelle OrderLine zur Verfügung, die durch OrderID eingeschränkt wurden. Wenn SUM in einer Zeile ausgeführt wird, befinden wir uns nicht in einer Pivot-Tabelle oder in einem Chart – sondern ausserhalb eines Filter-Kontextes. Oder anders ausgedrückt: Der Filter-Kontext hat keinen gesetzten Filter. Daher werden alle Werte der Tabelle summiert.

CALCULATE

Die Funktion Calculate kopiert den Filter-Kontext zum Zeitpunkt der Auswertung. Im Measure kann man diesen dann einfach ändern. Beispielsweise möchten wir (auch wenn unsinnig) immer den Wert von OrderID=1 erhalten. Folgendes Measure bewerkstelligt dies:

image

Kontext Transition

Calculate verwendet aber nicht nur den Filter-Kontext, sondern auch den Zeilenkontext. Wird Calculate in einem Zeilenkontext ausgeführt, dann wird der Zeilenkontext zum Filterkontext. Fügen wir eine berechnete Spalte hinzu mit folgender Formel:

Das Ergebnis ist dann wie folgt: image Der Zeilenkontext ist quasi ein Filter, der genau die aktuelle Zeile filtert. Wenn der Zeilenkontext zum Filterkontext wird, “sieht” Calculate nur noch die aktuelle Zeile. Daher ist jetzt die Summe von Wert immer der Wert der gleichen Spalte. SUM findet ja nur die eine Zeile.

Praktisches Beispiel mit RELATEDTABLE

Die Tabelle Order beinhaltet die Kopfdaten der Bestellung. Wenn wir dort den Gesamtwert der Bestellung in einer berechneten Spalte haben möchten, verwenden wir RELATEDTABLE (wenn Sie die Formel nicht kennen, lesen Sie diesen Artikel):

image Und jetzt nutzen wir die Kontext Transition, um das gleiche Ergebnis zu erhalten:

image Durch die Kontext Transition wird “so getan”, als ob der Benutzer in der beispielsweise ersten Zeile den Filter auf OrderID=1 gesetzt hätte. Dadurch, dass die Tabelle Order die Tabelle OrderLine filtert, erhält SUM nur noch die Zeilen mit OrderID=1. Daher ist das Ergebnis identisch.

Übrigens…

Zeilenkontexte haben Sie in jedem Iterator! Daher funktioniert diese Formel in einem Measure auch hervorragend: