DAX 篩選的守門神:FILTER 函數完全解析 (附練習檔)

CALCULATE 的簡單篩選不夠用?來認識門口的終極保鑣——FILTER 函數。本篇指南將用生動的「夜店保鑣」比喻,帶你深入 FILTER 作為迭代表函數的本質。你將學會處理簡單語法糖無法解決的「跨欄位比較」,以及用「量值」當作入場規則的終極技巧,讓你從此能應對任何複雜的篩選挑戰。

DAX 篩選的守門神:FILTER 函數完全解析 (附練習檔)

你好,我是 Kiro。

歡迎來到 DAX 這個高手雲集的專屬俱樂部。

在我們的《DAX 函數終極指南》中,我們將 CALCULATE 奉為 DAX 的王者,因為它能主宰整個舞池的氛圍(篩選上下文)。但在這個俱樂部裡,還有另一位你必須認識的關鍵人物——門口那位決定誰能進場的終極保鑣。這位保鑣,就是 FILTER 函數。

在俱樂部的日常營運中,大部分的賓客都持有標準的 QR Code 入場券。門口的「自動驗票閘門」可以快速掃描並放行符合資格的賓客。你寫下這樣的 DAX:

CALCULATE([總消費額], 'Dim_Members'[MembershipLevel] = "VIP")

這就像閘門只允許票券上標示為「VIP」的會員入場,簡單高效。這在 DAX 中被稱為「語法糖 (Syntactic Sugar)」。

語法糖是什麼?—— DAX 引擎背後的翻譯官

語法糖,就是一種讓開發者寫起來更簡單、讀起來更直觀的「簡化語法」。

事實上,當你寫下上面那段簡單的程式碼時,DAX 引擎在背後會自動將其「翻譯」成一個更完整、更底層的完整指令。

你寫的是:

CALCULATE(
    [總消費額],
    'Dim_Members'[MembershipLevel] = "VIP"
)

DAX 引擎真正執行的則是:

CALCULATE(
    [總消費額],
    FILTER(
        ALL('Dim_Members'[MembershipLevel]),
        'Dim_Members'[MembershipLevel] = "VIP"
    )
)

看到了嗎?簡單的 'Table'[Column] = "Value",其本質是一個包含了 ALLFILTER 函數,它執行的是一個「先移除該欄位上所有舊篩選,再應用新篩選」的覆蓋操作。

但這個便利的「自動閘門」是有極限的。如果今晚俱樂部舉辦一場特殊活動呢?

活動規則: VIP 會員可以攜帶賓客入場,但實際帶來的賓客數 (GuestsBrought),不能超過其會員等級的允許額度 (GuestAllowance)

這個規則,「自動驗票閘門」就處理不了了。它無法在掃描票券的瞬間,去比較兩個動態的數字。這時,就必須由門口那位經驗豐富的人工保鑣親自出馬,明確地寫出完整的 FILTER 規則。

這篇文章,就是要帶你徹底掌握這位守門神的所有規則。

🎁 邊讀邊做,學得更快! 本文提供完整的 Power BI 練習檔,免費訂閱我的電子報,即可立即前往會員資源中心下載,跟著文章一起動手操作!

📂 練習資料包含:
Dim_Members.xlsx
Fact_Attendance.xlsx
PBI_DAX_FILTER函數實戰_練習檔_V1.pbix

第一部分:FILTER 的核心身份 —— 他是一位嚴格的保鑣

在我們動手寫公式前,讓我們再次聚焦在「語法糖」背後那段真實的 DAX 程式碼,並用「保鑣」的比喻來徹底拆解它:

CALCULATE(
    [總消費額],
    FILTER(
        ALL('Dim_Members'[MembershipLevel]),
        'Dim_Members'[MembershipLevel] = "VIP"
    )
)

FILTER 就像一個夜店門口的保鑣,他是這樣解讀這條指令的:

情境: 今晚是跨俱樂部合作之夜,所有來賓都來自另一家合作俱樂部,在那裡他們的身份都是「Gold」等級。因此,初始的篩選上下文已經被設定為 'Dim_Members'[MembershipLevel] = "VIP"。但我們俱樂部今晚的規則是:只招待我們自己的「VIP」會員。
  1. ALL('Dim_Members'[MembershipLevel])
    • 保鑣的解讀: 「好的,老闆。我看到這群客人都戴著另一家店的『Gold』手環。但我的指令 (ALL 函數) 很清楚:無視那些手環。我只關心他們在我們俱樂部系統裡的真實身份。」
    • DAX 的語言: FILTER 的第一個參數是一張ALL 函數會提供一張移除了所有現有篩選的、包含 MembershipLevel 欄位所有唯一值的表(例如 'VIP', 'Regular', 'Gold')。它為保鑣提供了一份乾淨、完整的工作清單
  2. 'Dim_Members'[MembershipLevel] = "VIP"
    • 保鑣的解讀: 「了解。現在,我會拿著這份乾淨的工作清單,開始逐一檢查上面的每一個項目,我的入場規則是:只有當會員等級等於 "VIP" 時,我才會放行。」
    • DAX 的語言: FILTER 的第二個參數是一個篩選運算式FILTER迭代(逐行掃描)第一個參數提供的那張表,在每一列的列上下文中,判斷這個運算式是否為 TRUE

最終,保鑣會交給你一份新的、只包含所有通過檢查的賓客的名單。在這個情境中,即使來的人原本都是 "Gold",最終也只有在我們系統裡是 "VIP" 的人才能進場。這個「先移除舊標籤,再貼上新標籤」的過程,正是 CALCULATE 語法糖強大「覆蓋」能力的秘密。

現在你應該明白了,FILTER 函數的藍圖就是:

FILTER( <一張用來檢查的表>, <一個逐行判斷的規則> )


我們的分析場景:俱樂部的會員與入場紀錄

為了讓接下來的範例更具體,讓我們假設正在處理以下這個簡化的星型模型。我們的所有 DAX 公式,都將在這個結構上運作。

建立基礎量值:我們的計算起點

在開始分析前,我們需要先定義一個最基礎的量值,後續所有計算都將基於它。

總消費額 = SUM('Fact_Attendance'[TotalSpend])

第二部分:保鑣的日常工作 —— 執行「VIP 帶客規則」

這是 FILTER 最能體現其價值的場景:執行那些「自動驗票閘門」(語法糖) 無法處理的、需要逐行比較多個欄位的複雜規則。

  • 商業問題: 「我們想知道,所有符合帶客規則 (即 GuestsBrought <= GuestAllowance) 的入場紀錄,它們的總消費額是多少?」
  • 報表設定: 想像一個矩陣圖,資料列是 Dim_Members'[MembershipLevel],值是 [總消費額] 和我們即將建立的新量值。

DAX 公式:

符合資格入場總消費額 =
CALCULATE(
    [總消費額],
    FILTER(
        'Fact_Attendance',
        'Fact_Attendance'[GuestsBrought] <= 'Fact_Attendance'[GuestAllowance]
    )
)

一個關鍵的區別:為什麼這裡沒有 ALL

你可能已經注意到,這裡的 FILTER 直接作用在 'Fact_Attendance' 這張表上,而不是像語法糖那樣作用在 ALL('Fact_Attendance') 上。這是一個至關重要的區別。

保鑣的工作清單,是從哪來的?
  • FILTER( ALL(...) ):保鑣的工作清單來自總部,是完整的賓客總名單。他會忽略現場的排隊情況(初始篩選上下文),從頭開始檢查每一個人。
  • FILTER( 'Table', ...):保鑣的工作清單來自現場經理,是經理剛交給他的「預篩選名單」。他會尊重現場的排隊情況,只在他手上的那份小名單上,進行額外的檢查

DAX 引擎的思考流程 (以矩陣圖 "VIP" 那一列為例):

  1. DAX 引擎要計算 "VIP" 這一列的值。此時的初始篩選上下文'Dim_Members'[MembershipLevel] = "VIP"。這個篩選會透過關係傳遞到 'Fact_Attendance' 表。
  2. CALCULATE 看到 FILTER,將篩選任務交給保鑣。
  3. 保鑣的工作清單不是完整的入場紀錄,而是已經被篩選過的、只屬於 VIP 會員的入場紀錄 (現場經理交給他的「VIP 預篩選名單」)。
  4. 保鑣在這份小名單上,開始逐一檢查每一筆紀錄是否符合「帶客規則」。
  5. 檢查完畢後,保鑣交回了一份新的、更小的、只包含所有符合規則的 VIP 入場紀錄的「放行名單」
  6. CALCULATE 最終拿著這份精準的「放行名單」,計算出總消費額。

第三部分:保鑣的終極挑戰 —— 查驗「超級 VIP」

如果說上面的應用是保鑣的日常工作,那麼接下來的挑戰,就是俱樂部老闆下的特殊指令——一個需要動態判斷的、極度複雜的入場規則。

  • 商業問題: 「今晚只招待『超級 VIP』!規則是:找出那些『歷史總消費額』超過 $50,000 的『頂級會員』,並計算出這些頂級會員今晚的總消費額。」
  • 報表設定: 想像一個卡片圖,裡面只放我們即將建立的 [頂級會員總消費額] 這個量值。

這個規則的挑戰在於,入場的「條件」本身,就是一個需要即時計算的「量值」 ([總消費額] > 50000)。這相當於保鑣不能只看賓客今晚的穿著,還得立刻連線後台系統,查詢這位會員的歷史消費總額

DAX 公式:

頂級會員總消費額 =
CALCULATE(
    [總消費額],
    FILTER(
        VALUES('Dim_Members'[MemberName]),
        [總消費額] > 50000
    )
)

DAX 引擎的思考流程 (這一步很神奇,請仔細看):

  1. 在卡片圖的計算情境下,初始篩選上下文是空的
  2. CALCULATE 將任務交給保鑣 FILTER
  3. 保鑣這次拿到的名單,是來自 Dim_Members 表中一張不重複的「會員名稱」清單
  4. 【魔法的開端】 保鑣開始逐一檢查這份清單。當他檢查到會員「Kiro」這一列時,他需要知道 Kiro 是不是「超級 VIP」。
  5. 於是他會觸發一次「上下文轉換」,暫時將當前的列上下文 ('Dim_Members'[MemberName] = "Kiro"),轉換為一個篩選上下文
  6. 這個全新的篩選上下文中,[總消費額] 這個量值會被重新計算一次,得出只屬於「Kiro」的歷史總消費額
  7. 保鑣拿這個結果與 50000 進行比較。如果大於,則「Kiro」與「黃明宏」通過檢查,是今晚的超級 VIP。
  8. FILTER 將所有通過檢查的頂級會員名稱,彙集成一張新的 VIP 名單,交還給 CALCULATE
  9. CALCULATE 最終拿著這張頂級會員名單,篩選整個模型,並計算出他們的總消費額。

這個「在迭代中,為每一列觸發一次量值計算」的過程,是 DAX 中最高級、也最強大的技巧之一,而保鑣 FILTER 正是實現這一切的核心。


結論:你最可靠的守門神

現在,你應該能體เ會到為什麼我們稱 FILTER 為「DAX 的守門神」了。

它不僅僅是一個篩選器,它是一個強大的迭代器靈活的表產生器。它能與 CALCULATE 完美配合,讓你實現任何你能想像到的複雜入場規則——從簡單的數值比較,到跨欄位的動態比對,甚至是基於複雜量值的動態篩選。

掌握 FILTER,你將不再受限於「自動驗票閘門」的標準規則,而是能夠真正地讓數據根據你的商業邏輯,動態地回答更深層次的問題。


🚀 從心法到實戰,只差一步

恭喜你,你已經掌握了 FILTER 的核心運作邏輯!如果你渴望將這個強大的函數,應用在真實的商業專案中,我誠摯地邀請你加入我在 Hahow 好學校的線上課程。

【Power BI x AI 終極實戰:打造高效數據分析工作流】
✨ 在超過 5 小時的 DAX 專門單元中,我們將透過實戰案例,帶你逐行拆解 FILTERCALCULATE 的組合應用。
🎯 親手實作三大商業儀表板,將理論化為你的實戰超能力。

這不只是一堂工具課,更是一趟將你打造成真正數據專家的旅程。

👉 點擊這裡,立即加入超過千名學員的行列,將 DAX 從夢魘變為超能力!


🎁 想持續升級你的數據決策系統嗎?

覺得這篇文章對你有幫助嗎?這只是個開始。

免費加入,立即解鎖『會員資源中心』(內含完整電子書、練習檔案與更多專屬內容)!

你將不僅能立即下載排版精美的 【數據分析師的養成心法 (2025 終極指南)】 完整版電子書 (PDF) ,更重要的是,你將開始每週收到我的獨家框架、實踐案例與工具推薦。

讓我們一起,將數據轉化為智慧,打造屬於自己的理想人生。

Read more

《內容電力公司》實戰讀書筆記 (四):從發電廠到電力網,為你的王國建立真正的護城河

《內容電力公司》實戰讀書筆記 (四):從發電廠到電力網,為你的王國建立真正的護城河

讀完《內容電力公司》前幾章,我們已打造了內容事業的「發電廠」。但一座孤立的電廠無法照亮城市。這篇筆記將深入本書的「電網工程篇」(13-16章),探討如何透過建立直接的「訂閱者」關係,來回應職場上那份因價值觀被踐踏而生的痛苦,並策略性地運用 SEO 與社群媒體,為你的王國建立真正的護城河。

By Kiro