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