🧮 DAX

DAX — Công thức & Hàm

Các hàm DAX quan trọng nhất trong Power BI với cú pháp, ví dụ thực tế và tips sử dụng. Từ CALCULATE đến Time Intelligence.

CALCULATE — Hàm quan trọng nhất
Thay đổi filter context — backbone của mọi measure phức tạp
CALCULATE
Tính expression trong modified filter context
Core
Syntax
CALCULATE(expression, [filter1], [filter2], ...)
Revenue của Category = "Electronics"
Electronics Revenue =
CALCULATE(
    SUM(Sales[Revenue]),
    Sales[Category] = "Electronics"
)
Revenue cùng kỳ năm trước (PY)
Revenue PY =
CALCULATE(
    SUM(Sales[Revenue]),
    SAMEPERIODLASTYEAR(Date[Date])
)
Revenue ALL regions (bỏ filter vùng)
Total Revenue All Regions =
CALCULATE(
    SUM(Sales[Revenue]),
    ALL(Dim_Region)
)
Revenue tháng hiện tại
MTD Revenue =
CALCULATE(
    SUM(Sales[Revenue]),
    DATESMTD(Date[Date])
)
Hiểu cốt lõi: CALCULATE nhận filter context hiện tại, modify nó theo filter arguments, rồi tính expression trong context mới. Đây là lý do mọi measure Time Intelligence đều dùng CALCULATE.
🔍
FILTER, ALL, ALLEXCEPT
Kiểm soát filter context
FILTER
Trả về table đã lọc theo điều kiện
Table Function
Syntax
FILTER(table, condition)
Revenue của đơn hàng > 1 triệu
High Value Revenue =
CALCULATE(
    SUM(Sales[Revenue]),
    FILTER(Sales, Sales[Amount] > 1000000)
)
Customer có nhiều hơn 5 đơn hàng
Loyal Customer Rev =
CALCULATE(
    SUM(Sales[Revenue]),
    FILTER(
        VALUES(Sales[CustomerID]),
        CALCULATE(COUNTROWS(Sales)) > 5
    )
)
ALL / ALLEXCEPT / ALLSELECTED
Xóa filter context
Filter Modifier
% của tổng (market share)
% of Total =
DIVIDE(
    SUM(Sales[Revenue]),
    CALCULATE(
        SUM(Sales[Revenue]),
        ALL(Sales)   -- bỏ mọi filter
    )
)
% trong category (giữ filter Category)
% of Category =
DIVIDE(
    SUM(Sales[Revenue]),
    CALCULATE(
        SUM(Sales[Revenue]),
        -- giữ Category, bỏ filter Product
        ALLEXCEPT(Products, Products[Category])
    )
)
% trong slicer selection
% of Selection =
DIVIDE(
    SUM(Sales[Revenue]),
    CALCULATE(
        SUM(Sales[Revenue]),
        ALLSELECTED() -- giữ slicer filter
    )
)
📐
Aggregation Functions
SUM, AVERAGE, COUNT, SUMX, AVERAGEX, MAXX, MINX
SUMX / AVERAGEX / MAXX / MINX
Iterator — tính row by row rồi aggregate
Iterator
Syntax
SUMX(table, expression)
Khác nhau SUM vs SUMX: SUM(Sales[Revenue]) cộng trực tiếp cột Revenue. SUMX(Sales, Sales[Qty] * Sales[Price]) tính Qty×Price từng dòng trước, rồi cộng lại — dùng khi không có sẵn cột Revenue.
Tổng doanh thu (Qty × Price)
Revenue =
SUMX(
    Sales,
    Sales[Qty] * Sales[UnitPrice]
)
Average Order Value
AOV =
AVERAGEX(
    VALUES(Sales[OrderID]),
    CALCULATE(SUM(Sales[Revenue]))
)
Đơn hàng lớn nhất của mỗi customer
Max Order per Customer =
AVERAGEX(
    VALUES(Sales[CustomerID]),
    CALCULATE(
        MAXX(Sales, Sales[Amount])
    )
)
📅
Time Intelligence
YTD, MTD, PY, QTD, Rolling Average — cần Date Table
Bắt buộc: Phải có Date Table riêng được mark là "Date Table" (Model → Mark as date table). Không nên dùng cột Date trực tiếp từ fact table.
YTD / MTD / QTD
Tích lũy từ đầu năm/tháng/quý đến nay
Time Intel
Year-to-Date Revenue
YTD Revenue =
CALCULATE(
    SUM(Sales[Revenue]),
    DATESYTD(Date[Date])
)

-- hoặc dùng shorthand:
YTD Revenue v2 =
TOTALYTD(SUM(Sales[Revenue]), Date[Date])
Fiscal Year End = 31/3
Fiscal YTD =
TOTALYTD(
    SUM(Sales[Revenue]),
    Date[Date],
    "03/31"   -- fiscal year end
)
MTD và QTD
MTD Revenue =
TOTALMTD(SUM(Sales[Revenue]), Date[Date])

QTD Revenue =
TOTALQTD(SUM(Sales[Revenue]), Date[Date])
SAMEPERIODLASTYEAR / DATEADD
So sánh với kỳ trước
Time Intel
Revenue Year-over-Year
Revenue PY =
CALCULATE(
    SUM(Sales[Revenue]),
    SAMEPERIODLASTYEAR(Date[Date])
)

YoY Growth % =
DIVIDE(
    [Revenue] - [Revenue PY],
    [Revenue PY]
)
DATEADD — linh hoạt hơn
-- 3 tháng trước
Revenue 3M Ago =
CALCULATE(
    SUM(Sales[Revenue]),
    DATEADD(Date[Date], -3, MONTH)
)

-- 1 năm trước
Revenue 1Y Ago =
CALCULATE(
    SUM(Sales[Revenue]),
    DATEADD(Date[Date], -1, YEAR)
)
Rolling 3-Month Average
Rolling 3M Avg =
AVERAGEX(
    DATESINPERIOD(
        Date[Date],
        LASTDATE(Date[Date]),
        -3, MONTH
    ),
    CALCULATE(SUM(Sales[Revenue]))
)
🏆
RANKX, TOPN, HASONEVALUE
Ranking và conditional logic
RANKX
Xếp hạng trong nhóm
Ranking
Rank Product by Revenue
Product Rank =
RANKX(
    ALL(Products[ProductName]),
    CALCULATE(SUM(Sales[Revenue])),
    ,
    DESC,
    DENSE
)
Top 5 sản phẩm (dùng trong visual filter)
Is Top 5 =
IF(
    RANKX(
        ALL(Products[ProductName]),
        CALCULATE(SUM(Sales[Revenue])),
        , DESC
    ) <= 5,
    "Top 5", "Others"
)
Dùng RANKX với TOPN: Để filter visual chỉ hiện Top N, kéo Is Top 5 measure vào Visual Level Filter → "Top 5" → Apply.
SWITCH / IF
Conditional logic
Logic
SWITCH TRUE — nhiều điều kiện
Revenue Category =
SWITCH(
    TRUE(),
    [Revenue] >= 1000000, "Platinum",
    [Revenue] >= 500000,  "Gold",
    [Revenue] >= 100000,  "Silver",
    "Bronze"
)
Dynamic Measure selector
Selected Metric =
SWITCH(
    SELECTEDVALUE(MetricTable[Metric]),
    "Revenue",   [Total Revenue],
    "Orders",    [Total Orders],
    "Avg Order", [AOV],
    [Total Revenue]
)
Dynamic Metric Selector: Tạo bảng MetricTable với các tên metric, dùng SWITCH + SELECTEDVALUE để 1 visual hiển thị nhiều measure khác nhau tùy slicer.
📦
VAR / RETURN — Viết DAX sạch hơn
Lưu giá trị trung gian, tránh lặp code
VAR ... RETURN
Variables trong DAX
Best Practice
YoY Growth % với VAR
YoY Growth % =
VAR CurrentRev = SUM(Sales[Revenue])
VAR PrevRev =
    CALCULATE(
        SUM(Sales[Revenue]),
        SAMEPERIODLASTYEAR(Date[Date])
    )
RETURN
    IF(
        PrevRev = 0,
        BLANK(),
        DIVIDE(CurrentRev - PrevRev, PrevRev)
    )
Complex customer segmentation
Customer Segment =
VAR TotalRev = SUM(Sales[Revenue])
VAR OrderCount = COUNTROWS(Sales)
VAR LastOrder = MAX(Sales[OrderDate])
VAR DaysSince =
    DATEDIFF(LastOrder, TODAY(), DAY)
RETURN
    SWITCH(
        TRUE(),
        DaysSince <= 30 && TotalRev > 5000000,
            "Champion",
        DaysSince <= 90 && OrderCount > 5,
            "Loyal",
        DaysSince > 180,
            "At Risk",
        "Regular"
    )
Luôn dùng VAR khi: (1) Dùng cùng 1 expression >1 lần, (2) Measure phức tạp >3 functions lồng nhau, (3) Cần debug — VAR giúp tách từng bước.
🛡️
DIVIDE, BLANK, ISBLANK, IFERROR
Xử lý lỗi và null values
DIVIDE / BLANK / ISBLANK
Safety
Safe division — tránh divide by zero
-- Luôn dùng DIVIDE thay /
Profit Margin % =
DIVIDE([Gross Profit], [Revenue], 0)
-- arg 3 = giá trị trả về khi chia cho 0
Trả về BLANK thay vì 0
Revenue Safe =
IF(
    ISBLANK(SUM(Sales[Revenue])),
    BLANK(),
    SUM(Sales[Revenue])
)
-- BLANK() không hiển thị trong chart
-- giúp line chart không nối qua data trống
🔢
COUNT Functions
COUNTROWS, DISTINCTCOUNT, COUNTBLANK
COUNTROWS / DISTINCTCOUNT / COUNTBLANK
Count
Số đơn hàng, customers, products
Total Orders = COUNTROWS(Sales)

Unique Customers =
    DISTINCTCOUNT(Sales[CustomerID])

Active Products =
    COUNTROWS(
        FILTER(Products, Products[Status] = "Active")
    )
New vs Returning customers
New Customers =
CALCULATE(
    DISTINCTCOUNT(Sales[CustomerID]),
    FILTER(
        VALUES(Sales[CustomerID]),
        CALCULATE(
            MIN(Sales[OrderDate])
        ) >= MIN(Date[Date])
    )
)
Quick Reference — Cheat Sheet
Hàm Dùng khi Example
CALCULATEThay đổi filter contextRevenue cùng kỳ năm trước
SUMXTính row-level rồi sumQty × UnitPrice
FILTERFilter table theo điều kiện phức tạpĐơn > 1M, Customer VIP
ALLBỏ toàn bộ filter% of Total
ALLEXCEPTBỏ filter trừ 1 cột% of Category
DATESYTDYTD calculationRevenue từ đầu năm
SAMEPERIODLASTYEARSo sánh cùng kỳ năm trướcYoY Growth %
RANKXXếp hạngTop 10 products
SWITCH(TRUE())Multi-condition logicCustomer segment
DIVIDEChia an toànProfit margin %, tỉ lệ
DISTINCTCOUNTĐếm unique valuesUnique customers
VAR ... RETURNLưu biến trung gianMeasure phức tạp, debug