LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

在本教程中,我們將查看一段 DAX 代碼。您可能已經使用過類似的東西。或者,您可能會遇到它並對這段代碼的工作方式以及行上下文和過濾器上下文似乎如何在單個 DAX 代碼中相互交互感到困惑。無論哪種方式,本教程都將詳細介紹上述所有內容。您可以在本博客底部觀看本教程的完整視頻。

首先,我們要查看代碼本身。然後我們將回顧理論部分以更好地理解它。最後,我們將使用DAX Studio查看幕後的一切。

我們將要使用的數據模型基本上是一個簡單的銷售數據模型,其中包含 Dates、Sales 和 Products 表。Sales 表包含每一天的交易記錄。Products 表包含有關每個給定日期的產品銷售信息的信息。出於本教程的目的,Dates 表僅包含幾列。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

我們只對 Dates 表感興趣,但我們將使用 Sales 表和 Products 表來解釋過濾器上下文和行上下文如何借助關係進行傳播。

目錄

運行總計度量中的行上下文和篩選器上下文

現在,讓我們創建一個運行總計度量,因為它同時包含行和過濾器上下文。這是一個基本的運行總計度量,我在 FILTER 上使用 COUNTROWS,並使用 ALL 函數返回 Date 表中的所有年份。當我將該度量帶入下表時,您可以看到我們得到了預期的結果。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

現在讓我們嘗試分析該 DAX 代碼是如何工作的。

在度量中,您可以首先看到我們有 COUNTROWS,但這不是第一個被評估或被執行的函數。然後,我們有 FILTER 函數,然後是 ALL。評估順序中的第一件事是 ALL。ALL 通過忽略 ALL 函數之外存在的任何篩選器上下文來返回日期日曆年編號的所有唯一值。

因此,在指標中,我們有日曆年數字列,它正在主動過濾該列。但是由於 ALL 將忽略現有的過濾器上下文,我們將獲得該列的所有唯一值。

在第二個參數中,在行上下文中,我們寫了 Dates Calendar Year Number 應該小於 MAX Dates Calendar Year Number。現在,如果您是初學者並且仍在嘗試理解和學習 DAX,您可能會認為左側和 MAX 函數內部的引用都屬於同一列,並且是我們在 MAX 函數內部的同一張表所有功能。

但事實並非如此。行上下文中唯一屬於 ALL 函數的部分是我們在左側的部分。我們在 MAX 上擁有的那個是在過濾器上下文中而不是在行上下文中進行評估的。

因此,FILTER 嘗試在您在第一個參數中提供的表上創建行上下文,並且這部分代碼實際上是從該特定行上下文中檢索的。所以每一行,FILTER 迭代我們在 ALL 中擁有的那個表,然後我們能夠訪問我們當前正在迭代的所有值。

所以,在第一次迭代中,我們只有一個值。在第二次迭代中,我們有第二個值。但是當我們寫 MAX 時,它獨立於我們使用 FILTER 函數創建的行上下文。因此 MAX 正在由我們在該矩陣中使用的當前年份數字創建的過濾器上下文中進行評估。

當我們在 2006 年時,MAX 將返回 2006,而當前行可以是 2006、2007 或 2008。FILTER 將返回滿足我們在第二個參數中指定的條件的表。當我們移動到 2007 年時,MAX 將返回 2007。在 2008 年,它將返回 2008。根據所有小於 MAX 函數返回值的值,FILTER 將返回一個桌子。

為了證明 MAX 不依賴於行上下文,我們可以將這段 DAX 代碼分成幾個變量。然後,我們就能明白,左邊和右邊的column reference是不一樣的。

所以,讓我們創建一個變量。

正如您在下面的度量中看到的,我創建了三個變量 ( )。然後我最後添加了 FILTER 代碼和一個使用COUNTROWS的變量 Result 。當我在下表中使用此度量時,您會發現沒有任何變化。結果還是一樣。我們仍然得到與之前相同的運行總數。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

如果我們返回代碼並嘗試檢索第一個變量的值並確認這一點,您可以看到對於每一行,我們得到的是同一年。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

所以,希望我能夠向您解釋 MAX 函數,在此特定代碼中,實際上並不依賴於其值的真實上下文。如果您想簡化對評估上下文的理解,您始終可以將代碼分成幾個變量,以便您可以了解評估順序以及代碼是如何執行的。

現在,我想向您展示一個場景,其中 MAX 函數將依賴於 FILTER 函數創建的行上下文。

那麼,讓我們回到那個衡量標準。讓我們複製它,而不是最後可見年份,我將使用 MAX Dates Calendar Year Number。當我把它帶入矩陣時,你可以看到我們得到了一個空白。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

為什麼?

問題是我們多年來一直在迭代,CALCULATE 所做的是將當前迭代的行轉換為等效的篩選器上下文。

如果我在這裡寫一個等號,你可以看到我們得到七、七、七。

為什麼?

讓我創建一個新的計算表,以便您可以輕鬆了解正在發生的事情。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

我會去創建一個新表。接下來,我將在 ALL Dates Calendar Year Number 上寫入然後,我將編寫 Max Year,然後我將對日期日曆年編號的 MAX 使用 CALCULATE。現在您可以看到,對於每一行,我們都在重複相同的值。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

由於這些數字並不嚴格小於它們本身,因此我們得到一個空白。但是當我們使用等於 (=) 時,我們是說所有小於 2011 的值都得到 7。

此外,即使您使用諸如 Max Year 之類的度量參考,此代碼也不會起作用。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

如果我點擊確認,你會看到我們仍然沒有得到任何東西。這是因為當我們寫 Max Year 時,我們只是在寫 CALCULATE MAX Dates Calendar Year Number。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

度量參考總是在其外部有一個 CALCULATE。因此,此度量正在啟動上下文轉換,將當前迭代的行轉換為篩選器上下文。

但是,如果您受到限制並且必須使用度量參考,那麼您可以做的就是將該度量存儲在一個變量中。正如您所知,變量是常量,它們無法創建上下文轉換。因此它無法將行上下文轉換為篩選器上下文。

因此,這是行上下文和篩選器上下文如何在 DAX 代碼中相互交互的快速演示。

現在讓我們去 DAX Studio 了解幕後發生的事情。

使用 DAX Studio 了解行上下文和篩選器上下文

讓我們轉到外部工具並啟動 DAX Studio。我們需要在Query PlanServer Timings的幫助下連接到 LuckyTemplates 文件。

然後,我將創建一個查詢度量。我將在 Dates 表中寫入 DEFINE MEASURE,Dates Running Total。然後,我將使用我們擁有的原始代碼。

因為我們應該返回一個表,所以我們可以寫 EVALUATE。最後,我們將使用 SUMMARIZECOLUMNS 創建表。因此,我們將編寫日期日曆年編號和虛擬列,這將是運行總計。然後,我可以將類似 DT 的內容寫為 DAX Studio 關鍵字。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

如果我執行這段代碼,你會看到代碼是完整的,我們仍然得到與在 LuckyTemplates 中看到的相同的結果。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

現在,讓我們轉到查詢計劃以了解幕後發生的事情。讓我們看看 MAX 函數是否真的依賴於行上下文。讓我們轉到邏輯查詢計劃,因為物理查詢計劃通常更複雜並且有點難以閱讀。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

您可以看到第一行的第一個運算符是GroupSemiJoin,SUMMARIZECOLUMNS 使用它在兩列之間創建內部連接。

然後,為了加入這些列,有Scan_Vertipaq,這是我們在分析服務中擁有的存儲引擎。我們可以看到它說我們需要一列,即 Dates Calendar Year Number。在 LuckyTemplates 中,您可以看到在矩陣上,我們有這個日曆年編號列,它用作對我們報表的訪問。

接下來,我們在度量中使用COUNTROWS 函數作為頂級運算符,然後 COUNTROWS為過濾器調用FILTER 函數。又是一個Scan_Vertipaq,它說 RequiredCols 是 Dates Calendar Year Number。

第 2 行和第 5 行相同,但第一個 Scan_Vertipaq 標記為零,而第二個標記為 1。這意味著我們正在訪問的列,在 ALL 函數的幫助下,與我們在 SUMMARIZECOLUMNS 函數中擁有的列分開提取。

然後,有一個LessThan運算符。在下一行中,我們可以看到行上下文和 MAX 函數之間有一個比較

接下來是Max_Vertipaq。所以,我們實際上是從存儲引擎中提取最大值。在右側,您可以看到上面寫著 DependOnCols Dates Calendar Year Number。這是我們需要記住的最重要的事情。前面我說過MAX函數對行上下文沒有依賴,這就是事實證明。

所以,這裡說的是零。

我們在哪裡找到零?

在頂部(第二行),這是為 SUMMARIZECOLUMNS 提取的。這意味著 MAX 函數不依賴於行上下文,但它實際上依賴於我們在該表中的列(日曆年編號)。所以該表實際上是在創建過濾器上下文。

簡而言之,MAX 函數依賴於過濾器上下文而不是行上下文。

接下來,您可以看到為了計算 Max_Vertipaq,我們有一個Scan_Vertipaq,它表示 DependOnCols 零 (0) 日期日曆年編號。然後,還有其他幾個列需要列。

現在讓我們看一下代碼的可變版本。我沒有返回 LastVisibleYear,而是返回 COUNTROWS 版本或 Result 變量,您可以看到我們仍然得到相同的結果。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

如果我們查看查詢計劃,您會發現它有點長,但更容易閱讀。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

最後,這也是代碼的計算版本

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文

這就是它的邏輯查詢計劃的樣子。

LuckyTemplates DAX 代碼中的行上下文和過濾器上下文


DAX LuckyTemplates:什麼是行上下文
LuckyTemplates 中篩選上下文的介紹
什麼是上下文轉換及其重要性?

結論

在本教程中,我解釋了給定函數如何與行上下文交互以及如何不能交互。我還向您展示瞭如何在這種情況下在過濾器上下文而不是行上下文中評估 MAX。

重要的是要始終記住,過濾上下文過濾整個模型,行上下文只迭代給定的表,從不過濾模型。過濾器上下文不會迭代表。

希望本教程對您有所幫助。請繼續關注我們即將發布的DAX Studio代碼。我們將更深入地研究類似的場景。我們還將教您如何優化 DAX 代碼。


什麼是 Python 中的自我:真實世界的例子

什麼是 Python 中的自我:真實世界的例子

什麼是 Python 中的自我:真實世界的例子

如何在 R 中保存和加載 RDS 文件

如何在 R 中保存和加載 RDS 文件

您將學習如何在 R 中保存和加載 .rds 文件中的對象。本博客還將介紹如何將對像從 R 導入 LuckyTemplates。

回顧前 N 個工作日——DAX 編碼語言解決方案

回顧前 N 個工作日——DAX 編碼語言解決方案

在此 DAX 編碼語言教程中,了解如何使用 GENERATE 函數以及如何動態更改度量標題。

在 LuckyTemplates 中使用多線程動態視覺技術展示見解

在 LuckyTemplates 中使用多線程動態視覺技術展示見解

本教程將介紹如何使用多線程動態可視化技術從報告中的動態數據可視化中創建見解。

LuckyTemplates 篩選上下文簡介

LuckyTemplates 篩選上下文簡介

在本文中,我將貫穿過濾器上下文。篩選上下文是任何 LuckyTemplates 用戶最初應該了解的主要主題之一。

使用 LuckyTemplates 在線服務中的應用程序的最佳技巧

使用 LuckyTemplates 在線服務中的應用程序的最佳技巧

我想展示 LuckyTemplates Apps 在線服務如何幫助管理從各種來源生成的不同報告和見解。

隨著時間的推移分析利潤率變化——使用 LuckyTemplates 和 DAX 進行分析

隨著時間的推移分析利潤率變化——使用 LuckyTemplates 和 DAX 進行分析

了解如何在 LuckyTemplates 中使用度量分支和組合 DAX 公式等技術計算利潤率變化。

DAX Studio 中數據緩存的物化想法

DAX Studio 中數據緩存的物化想法

本教程將討論數據緩存物化的想法,以及它們如何影響 DAX 在提供結果時的性能。

使用 LuckyTemplates 進行業務報告

使用 LuckyTemplates 進行業務報告

如果直到現在你還在使用 Excel,那麼現在是開始使用 LuckyTemplates 來滿足你的業務報告需求的最佳時機。

什麼是 LuckyTemplates 網關?所有你必須知道的

什麼是 LuckyTemplates 網關?所有你必須知道的

什麼是 LuckyTemplates 網關?所有你必須知道的