Trong thế giới phân tích dữ liệu và Business Intelligence, Power BI đã trở thành một công cụ quan trọng, giúp các chuyên gia và doanh nghiệp hiểu rõ dữ liệu của họ. Trong Power BI, ngôn ngữ DAX (“Data Analysis Expressions”) đóng vai trò cốt lõi trong việc xây dựng các biểu thức tính toán và mâu lệnh. Một trong những khái niệm quan trọng nhất trong DAX là Context Transition.
1. Context transition là gì?
Trước khi đi vào khái niệm Context transition, chúng ta cần hiểu về một số loại ngữ cảnh trong DAX.
Row Context (Ngữ cảnh dòng)
Row Context liên quan đến việc áp dụng các tính toán trên từng dòng của một bảng. Điều này thường xảy ra khi bạn sử dụng các hàm như SUMX, AVERAGEX hoặc khi tính toán trong các cột được tính toán (Calculated Columns).
Ví dụ, nếu bạn tạo ra một cột tính toán để tính thuế (giả sử là 8%) dựa trên giá trị Sales[Amount], công thức dưới dạng:
Tax = Sales[Amount] * 0.08
Lúc này, Row Context sẽ tự động áp dụng trên từng dòng và Sales[Amount] được tính riêng lẻ cho mỗi dòng dữ liệu.
Filter Context (Ngữ cảnh bộ lọc)
Filter Context liên quan đến việc áp dụng các bộ lọc trên dữ liệu để xác định các giá trị cần tính toán. Filter Context thường được sử dụng trong các measures và khi bạn áp dụng bộ lọc trực tiếp trong báo cáo (ví dụ: slicers, visual filters, …).
Ví dụ, bạn muốn tính tổng doanh thu cho một khách hàng cụ thể, bạn có thể sử dụng công thức:
Total Sales for Customer =
CALCULATE(
SUM(Sales[Amount]),
Sales[CustomerID] = “C001”
)
Trong trường hợp này, Filter Context được áp dụng để chỉ chọn các dòng có CustomerID = “C001”.
Mặc dù Row Context và Filter Context hoạt động độc lập, chúng có thể tương tác với nhau thông qua Context Transition. Đây là một quá trình cho phép chuyển đổi Row Context thành Filter Context, giúp bạn khai thác tối đa khả năng phân tích của DAX.
Context Transition
Context Transition trong DAX là khả năng chuyển đổi ngữ cảnh dòng (Row Context) thành ngữ cảnh bộ lọc (Filter Context). Hiểu đơn giản, khi Context Transition được kích hoạt, những dòng dữ liệu hiện hành sẽ được chuyển đổi thành các bộ lọc áp dụng trong bối cảnh tính toán.
Context Transition được sử dụng đặc biệt phổ biến trong các hàm như CALCULATE và CALCULATETABLE. Khi hai hàm này được gọi, chúng chuyển Row Context sang Filter Context, giúp mở rộng tính linh hoạt và đảm bảo kết quả tính toán chính xác.
2. Lợi ích và vai trò của Context Transition
- Tăng độ linh hoạt trong tính toán.
- Phát hiện quan hệ tiềm ẩn trong dữ liệu: Context Transition giúp bạn khám phá được những mối quan hệ phức tạp giữa các tập hợp dữ liệu bằng cách cho phép chuyển đổi ngữ cảnh một cách linh hoạt.
- Đảm bảo kết quả tính toán chính xác.
3. Cách hoạt động của Context Transition
Khi sử dụng hàm CALCULATE, DAX sẽ chuyển ngữ cành dòng (Row Context) thành ngữ cảnh bộ lọc (Filter Context) bằng cách tạo ra các bộ lọc tương ứng với các dòng hiện hành. Điều này cho phép các phép tính như SUM, AVERAGE hay COUNT hoạt động với ngữ cảnh đúng.
Hình ảnh trên minh họa một cách rõ ràng và chi tiết cách hoạt động của Context Transition trong DAX, cho thấy quá trình chuyển đổi từ Row Context sang Filter Context để thực hiện các phép tính tổng hợp chính xác. Bảng dữ liệu ban đầu là Customer Table, chứa thông tin về khách hàng với các cột Key (mã định danh), Name (tên khách hàng), và Country (quốc gia cư trú).
Quá trình Context Transition diễn ra khi dữ liệu của từng dòng trong Row Context được chuyển đổi thành các bộ lọc tương ứng trong Filter Context. Ví dụ, dòng dữ liệu của Bob với Key = 225 sẽ tạo ra Filter Context giới hạn dữ liệu chỉ bao gồm các giao dịch liên quan đến Bob. Những Filter Context này được áp dụng lên bảng dữ liệu chính, chẳng hạn như Sales Table, để giới hạn phạm vi tính toán chỉ trong các giao dịch tương ứng với từng khách hàng.
Kết quả của quá trình này được minh họa trong bảng tổng hợp bên trên, nơi hiển thị Sales Amount (tổng doanh thu) và Average Customer Sales (doanh thu trung bình của khách hàng) cho từng thương hiệu.
4. Ví dụ minh họa
Mình đang có bộ dữ liệu bao gồm các bảng như bảng Sales (Doanh số), bảng thông tin khách hàng, sản phẩm, cửa hàng, … và giữa chúng được thiết lập các mối quan hệ như hình dưới đây:
Ví dụ 1: Tính tổng doanh thu từ các khách hàng có thu nhập cao trong chiến dịch khuyến mãi
Chúng ta hãy cùng bắt đầu với một ví dụ cụ thể. Giả sử, bạn cần tính toán tổng doanh thu từ các khách hàng có thu nhập cao (trên $100,000/năm) tham gia một chiến dịch khuyến mãi cụ thể nào đó.
Đầu tiên, mình sẽ viết hàm để tính doanh thu:
Sales Amount = SUMX ( Sales, Sales[Quantity] * Sales[Net Price] )
Từ đây, ta có thể sử dụng hàm CALCULATE để tính toán yêu cầu của đề bài:
High Income Customer Sales From Promotion =
CALCULATE(
[Sales Amount],
Customer[Yearly Income] > 100000,
Promotion[Promotion] = “Asian Summer Promotion”
)
Trong đó, bộ lọc chính ở đây là Customer[Yearly Income] > 100000, đại diện cho phân khúc khách hàng có thu nhập cao; Promotion[Promotion] = “Asian Summer Promotion” dùng để chọn các giao dịch nằm trong chiến dịch khuyến mãi này.
CALCULATE đã chuyển Row Context trong các bảng Customer và Promotion thành Filter Context, đảm bảo việc chỉ chọn các giao dịch thỏa mãn các điều kiện bộ lọc trên. Kết quả ta thu được sẽ là tổng doanh thu được đánh giá theo chiến dịch “Asian Summer Promotion” và nhóm khách hàng thu nhập cao.
Ví dụ 2: Minh họa bằng Calculated Columns
Để tiếp tục tìm hiểu cách Context Transition hoạt động, chúng ta sẽ phân tích một ví dụ cụ thể trong trường hợp tính tổng doanh thu (Total Sales) cho từng sản phẩm trong bảng Product. Qua ví dụ này, bạn sẽ hiểu rõ hơn sự khác biệt khi sử dụng và không sử dụng Context Transition, cũng như cách nó ảnh hưởng đến kết quả tính toán.
Ở ví dụ này, mình sẽ tạo các Calculated Columns trong bảng Product để tính giá trị Total Sales Amount từ bảng Sales, biết rằng 2 bảng này có mối quan hệ one to many từ Product đến Sales thông qua cột ProductKey.
Công thức 1: Không sử dụng Context Transition
Grand Total Sales Amount =
SUM(Sales[Net Price]) * [Sales Qty]
Nguyên lý hoạt động:
- SUM(Sales[Net Price]): Tính tổng toàn bộ giá trị Net Price trong bảng Sales, không áp dụng bất kỳ bộ lọc nào từ bảng Product.
- [Sales Qty]: Giá trị số lượng bán hàng từ cột tương ứng trong bảng Product.
Kết quả:
- Công thức này không lọc bảng Sales theo ProductKey, nghĩa là doanh thu được tính trên toàn bộ dữ liệu trong bảng Sales.
- Kết quả hoàn toàn sai vì không có bất kỳ bộ lọc nào được áp dụng trên bảng Sales.
- Điều này xảy ra do Row Context không ảnh hưởng đến dữ liệu trong bảng Sales, và công thức không sử dụng Context Transition.
Công thức 2: Sử dụng Context Transition
Grand Total Sales Amount CALCULATE =
CALCULATE(
SUM(Sales[Net Price]) * [Sales Qty]
)
Nguyên lý hoạt động:
- CALCULATE: Tự động chuyển đổi Row Context của từng dòng trong bảng Product thành Filter Context.
- Filter Context này được áp dụng lên bảng Sales, chỉ giữ lại các giao dịch có ProductKey khớp với ProductKey của sản phẩm hiện tại.
- SUM(Sales[Net Price]): Tính tổng giá trị Net Price, nhưng lần này chỉ tính trên các dòng được lọc bởi ProductKey của sản phẩm hiện tại.
Kết quả: Kết quả trả về chính xác cho từng dòng, thể hiện tổng doanh thu của từng sản phẩm dựa trên các giao dịch liên quan trong bảng Sales. Kết quả chính xác nhờ Context Transition, vì ngữ cảnh dòng (Row Context) đã được chuyển đổi thành bộ lọc (Filter Context), giúp công thức chỉ tính toán các giao dịch liên quan đến từng sản phẩm.
Ví dụ 3: Minh họa giá trị cộng dồn qua thời gian với Context Transition
Trong bài toán này, chúng ta sẽ tính tổng doanh thu cộng dồn (Cumulative Sales) qua thời gian dựa trên hai bảng Sales và Date, áp dụng hai phương pháp khác nhau để làm rõ sự khác biệt trong cách xử lý Context Transition.
Trước hết, để tính doanh thu cộng dồn, chúng ta cần xác định ngày lớn nhất mà phép tính được thực hiện – được gọi là Max Date. Một measure phụ được viết như sau:
MaxDate =
MAX (‘Date'[Date])
Measure này trả về ngày lớn nhất trong ngữ cảnh hiện tại của bảng Date, và nó sẽ được sử dụng trong phương pháp đầu tiên để minh họa Context Transition.
Với Cumulative Sales 1, công thức sử dụng [MaxDate] bên trong FILTER để tính toán doanh thu tích lũy. Công thức được viết như sau:
Cumulative Sales 1 =
CALCULATE(
[Total Sales],
FILTER(
ALL(‘Date’),
‘Date'[Date] <= [MaxDate]
)
)
Trong công thức này, [MaxDate] được gọi bên trong CALCULATE, và điều này dẫn đến Context Transition. Khi Context Transition xảy ra, Row Context của hàm FILTER được chuyển thành Filter Context, và điều này khiến [MaxDate] luôn trả về giá trị ngày đang được lặp trong vòng lặp hiện tại. Kết quả là FILTER không thực sự lọc đúng các dòng thời gian mong muốn, mà trả về toàn bộ bảng Date. Do đó, giá trị của Cumulative Sales 1 là tổng doanh thu toàn bộ, không phản ánh đúng giá trị cộng dồn theo thời gian.
Ngược lại, Cumulative Sales 2 sử dụng cách tiếp cận khác, tính giá trị lớn nhất của cột Date[Date] trực tiếp trong FILTER. Công thức được viết như sau:
Cumulative Sales 2 =
CALCULATE(
[Total Sales],
FILTER(
ALL(‘Date’),
‘Date'[Date] <= MAX(‘Date'[Date])
)
)
Trong công thức này, MAX(‘Date'[Date]) được tính trực tiếp trong FILTER và không kích hoạt Context Transition. Bộ lọc được áp dụng chính xác, chỉ giữ lại các dòng trong bảng Date có ngày nhỏ hơn hoặc bằng ngày hiện tại trong ngữ cảnh báo cáo (outer filter). Kết quả của Cumulative Sales 2 phản ánh chính xác giá trị cộng dồn qua các ngày.
Sự khác biệt giữa hai phương pháp trở nên rõ ràng khi xem kết quả trong bảng dữ liệu. Ví dụ, trong năm 2007, Cumulative Sales 1 trả về giá trị cố định là 30,591,344 – tổng doanh thu toàn bộ, vì bộ lọc không hoạt động đúng. Trong khi đó, Cumulative Sales 2 cho thấy giá trị cộng dồn thực sự qua từng tháng, bắt đầu từ 794,248 vào tháng 1 và tăng dần lên 11,309,946 vào tháng 12. Kết quả của Cumulative Sales 2 là chính xác, phản ánh đúng xu hướng tích lũy doanh thu theo thời gian.
5. Kết luận
Context Transition là một trong những khái niệm cốt lõi và mạnh mẽ nhất trong DAX, đồng thời cũng là một trong những khía cạnh dễ gây nhầm lẫn nếu không hiểu rõ. Qua các ví dụ minh họa trong bài viết, chúng ta đã thấy được cách Context Transition chuyển đổi Row Context thành Filter Context, từ đó ảnh hưởng trực tiếp đến cách các phép tính DAX hoạt động.
Lợi ích của Context Transition không chỉ dừng lại ở việc tăng độ linh hoạt trong tính toán, mà còn giúp bạn phát hiện các mối quan hệ tiềm ẩn trong dữ liệu và đảm bảo rằng kết quả được tính toán chính xác trong các tình huống phức tạp. Điều này đặc biệt quan trọng khi làm việc với các tập dữ liệu lớn và đa chiều trong Power BI.
Cuối cùng, để sử dụng Context Transition hiệu quả, bạn cần hiểu rõ ngữ cảnh của công thức DAX, cách các hàm như CALCULATE và FILTER hoạt động, và khi nào nên hoặc không nên áp dụng Context Transition. Với sự hiểu biết này, bạn sẽ có thể khai thác toàn bộ sức mạnh của DAX, biến Power BI thành một công cụ phân tích dữ liệu thực sự mạnh mẽ và đáng tin cậy.