
Văn bản của bài đăng trên blog cần được chỉnh sửa ở đây. Bạn có thể thêm văn bản, hình ảnh, phòng
Khám phá Series “DAX Recipes” – Bí quyết biến dữ liệu thành sức mạnh cạnh tranh!
Bạn muốn làm chủ Power BI? Bạn muốn biến dữ liệu thành những câu chuyện và quyết định kinh doanh thông minh? Series “DAX Recipes” chính là “vũ khí bí mật” dành cho bạn!
Tại đây, chúng tôi chia sẻ những công thức DAX đã được kiểm chứng trong thực tế – từ các tình huống phân tích phổ biến đến các “mẹo” tối ưu báo cáo giúp bạn nâng tầm kỹ năng phân tích dữ liệu. Mỗi bài viết là một “công thức thành công”, kết hợp giữa ví dụ thực tế, phân tích chuyên sâu và hướng dẫn chi tiết, giúp bạn nhanh chóng vận dụng DAX để giải quyết mọi bài toán trong công việc.
Đồng hành cùng “DAX Recipes”, bạn sẽ tự tin xây dựng những báo cáo ấn tượng, đưa ra quyết định dựa trên dữ liệu và khẳng định giá trị của mình trong tổ chức!
trưng bày, tiêu đề, cột, biểu mẫu đơn giản, mọi thứ đều giống như trên các trang thông thường
Thành phần:
Kết quả đạt được:
Giá trị trung bình mỗi ngày.
Ví dụ, nếu bạn có doanh số trong 30 ngày, trung bình sẽ được tính bằng cách lấy tổng doanh số của 30 ngày chia cho 30.
Phương pháp thực hiện:
Với mỗi tổ hợp tháng và năm trong bảng, quá trình diễn ra như sau:
- Hàm VALUES sẽ tạo ra một bảng tạm với danh sách các ngày duy nhất từ bảng Calendar.
- Measure Total Sales sẽ được đặt trước từng ngày trong bảng tạm này (giống như một bảng pivot ẩn tạo ra ở hậu trường với từng tổ hợp).
- Hàm AVERAGEX sẽ tính giá trị trung bình cho mỗi tập dữ liệu được chọn này.
Lưu ý:
Giá trị trung bình này không bao gồm những ngày không có số liệu (blank). Nếu bạn muốn tính trung bình kể cả các ngày trống, hãy tham khảo công thức khác ở phần tiếp theo.
Giải thích chi tiết:
Có thể bạn chưa hiểu hết lý do vì sao bài viết này lại sử dụng công thức trên và cho ra kết quả đúng như mong muốn. Vì vậy, với mỗi DAX Recipe do ERX Việt Nam biên soạn, chúng tôi sẽ bổ sung phần giải thích cực kỳ dễ hiểu ngay phía dưới, giúp bạn nắm chắc bản chất vấn đề.
Đầu tiên chúng ta sẽ trở lại với bảng Matrix kết quả mẫu mình đã cung cấp trong bài.
Ví dụ bạn đang ở dòng Month Year = "31/Oct/2022" (Đây là Filter Context tới từ bên trong của Visual - Ta có thể gọi nó là Inner Filter)
Dưới đây là Measure mà chúng ta đã viết: AVERAGEX(VALUES (d_Calendar[Date]), [Total Sales])
Khi viết như thế này thì kết quả bạn nhận được sẽ là gì?
Đầu tiên ta phải để ý là AVERAGEX là 1 hàm Iterator (Hiểu là phép tính Expression sẽ chạy qua từng dòng trong 1 Table mà bạn cung cấp). Mà tất cả các hàm Iterator như SUMX, AVERAGEX, CONCATENATEX, ... đều sẽ áp dụng Row Context. Như vậy phép tính [Total Sales] sẽ được áp dụng cho từng dòng của table VALUES(d_Calendar[Date]) mà chúng ta đã cung cấp.
Vậy VALUES(d_Calendar[Date]) sẽ trả về cái gì? Các bạn hãy xem hình ảnh dưới đây nếu không có Inner Filter Context ở trên nhé.
Bạn có thể thấy danh sách chúng ta thu được khi sử dụng VALUES(d_Calendar[Date]) sẽ là 1 bảng chứa các giá trị không trùng lặp của cột [Date] bảng d_Calendar.
Nhiều bạn sẽ thắc mắc tại sao không viết luôn d_Calendar[Date] mà phải viết VALUES(d_Calendar[Date]) vì bản chất d_Calendar[Date] đã là các giá trị không trùng lặp rồi. Đâu cần phải áp dụng VALUES để lấy các giá trị không trùng lặp nữa? Chẳng lẽ việc làm này là vô ích?
Bạn có thể thử bỏ đi VALUES trong công thức trên và sẽ được trả về lỗi như hình dưới đây:
Tạm dịch như sau: Một giá trị duy nhất cho cột 'Date' trong bảng 'd_Calendar' không thể xác định được. Điều này xảy ra khi một measure hoặc công thức tham chiếu tới một cột có nhiều giá trị, mà lại không chỉ rõ cách tổng hợp (như min, max, count hoặc sum) để lấy ra một kết quả duy nhất.
Nếu bạn viết d_Calendar[Date] trong công thức DAX mà không có ngữ cảnh duy nhất (ví dụ: 1 ngày), DAX sẽ bị lúng túng vì không biết lấy giá trị nào.
Vì vậy, khi cần làm việc với nhiều dòng, hãy dùng hàm như:
- MIN(d_Calendar[Date])
- MAX(d_Calendar[Date])
hoặc (quan trọng nhất!) dùng VALUES để tạo bảng con (dùng cho iterator như AVERAGEX, SUMX, CONCATENATEX, ...)
Từ đây bạn có thể hiểu rằng khi áp dụng với các hàm Iterator và muốn tham chiếu tới 1 cột nào đó thì bạn hãy áp dụng hàm VALUES nhé.
Tiếp tục phần trên, ta sẽ tiếp tục thực hiện Filter Context theo d_Calendar[Year Month] = DATE(2022, 10, 31) chúng ta sẽ thu được Table nào khi áp dụng VALUES('Calendar'[Date]) nhé.
Trở lại với bài trên. Ta có thể thấy khi áp dụng vào Inner Filter Context mà ta đã nói từ đầu bài thì VALUES(d_Calendar[Date]) sẽ tạo ra 1 danh sách các ngày không trùng lặp trong tháng 10 của năm 2022.
Lúc này thì AVERAGEX sẽ đi qua từng dòng trong bảng được tạo thành. Vì bảng Calendar có mối quan hệ One to Many với bảng Sales.
Khi đó nếu bạn đang ở dòng d_Calendar[Date] = DATE(2022,10,11) thì khi đó bảng f_Sales sẽ bị Filter tương ứng. Lúc này các giao dịch Sales trong ngày DATE(2022,10,11) sẽ được gom lại hết. Và đến lúc này Expression [Total Sales] sẽ được tiến hành.
Lúc này trước khi tính AVERAGE doanh thu của 30 ngày thì chúng ta sẽ có kết quả như hình dưới đây.
Như bạn thấy chúng ta sẽ có được Total Sales theo từng ngày. Và đây là lúc AVERAGEX làm nốt việc của nó đó là tính trung bình doanh thu theo doanh thu từng ngày phát sinh.
Nếu ta thay bằng SUMX thì kết quả thu được không phải trung bình mà sẽ là tổng doanh thu.
Vậy tại sao phải VALUES(d_Calendar[Date]).
Tại sao không thể viết AVERAGEX(f_Sales, [Total Sales])
Nếu viết như trên thì bạn đang tính tổng doanh thu Sales phát sinh. Ví dụ thời điểm tháng 10 năm 2022 đi. Nhưng sau đó AverageX sẽ không có vụ SUMMARIZE dữ liệu theo từng ngày như vậy. Mà nó sẽ lấy tổng doanh thu chia cho tổng số đơn hàng phát sinh trong thời điểm tháng 10 năm 2022. Khi đó kết quả bạn thu được sẽ là doanh thu trung bình trong tháng (Tính theo đơn hàng) chứ không phải tính theo ngày.
Mình sẽ cho bạn xem kết quả so sánh ngay dưới đây. Bạn sẽ thấy kết quả chênh lệch nhau khá lớn đúng không nào.
please authorize