2026-08-09 · Power BI & Dashboard
Bạn có bảng bán hàng với hai cột Đơn giá và Số lượng, không có cột Thành tiền. Bạn viết Doanh thu = SUM(BanHang[DonGia] * BanHang[SoLuong]) cho nhanh. Power BI báo lỗi ngay: hàm SUM chỉ nhận một cột, không nhận một phép tính.
Đây là lúc gần như ai học DAX cũng gặp ngã rẽ đầu tiên. Nhiều người xử lý bằng cách tạo thêm một calculated column Thành tiền rồi SUM cột đó. Chạy được, ra đúng số, nhưng đã đi chệch hướng: file phình lên, và khi gặp bài toán phức tạp hơn một chút thì bế tắc hẳn.
Cách đúng là dùng SUMX. Bài này đội ngũ EzTech giải thích SUM và SUMX khác nhau ở đâu, iterator nghĩa là gì, khi nào bắt buộc phải dùng SUMX, và ba chỗ hay ra số sai nhất.
SUM cộng cột có sẵn, SUMX tính từng dòng rồi mới cộng
Chỉ cần nhớ đúng một câu này là đủ dùng cho 90% trường hợp.
SUM nhìn vào một cột và cộng các giá trị trong đó. Cột phải tồn tại thật trong mô hình. Nó không tính toán gì thêm, chỉ cộng.
SUMX duyệt qua từng dòng của một bảng, ở mỗi dòng nó tính biểu thức bạn đưa ra, rồi cộng tất cả kết quả lại. Cột Thành tiền không cần tồn tại, vì SUMX tự tính ra nó trong bộ nhớ ở từng dòng rồi bỏ đi.
Viết ra thì như sau:
Doanh thu = SUM(BanHang[ThanhTien])— cần có sẵn cột ThanhTien.Doanh thu = SUMX(BanHang, BanHang[DonGia] * BanHang[SoLuong])— không cần cột nào thêm.
SUMX luôn có hai phần: bảng để duyệt và biểu thức tính ở từng dòng. Thiếu một trong hai là sai cú pháp.
Iterator là gì và vì sao nó quan trọng
SUMX thuộc họ hàm mà dân làm DAX gọi là iterator, tức là hàm biết duyệt dòng. Dấu hiệu nhận biết rất dễ: tên kết thúc bằng chữ X. Ngoài SUMX còn có AVERAGEX, MINX, MAXX, COUNTX, CONCATENATEX, RANKX.
Điểm chung của cả họ này là chúng tạo ra row context, hiểu nôm na là "biết đang đứng ở dòng nào". Nhờ vậy, bên trong biểu thức bạn được phép gọi thẳng tên cột như [DonGia] và Power BI hiểu là đơn giá của đúng dòng đang duyệt.
Measure bình thường thì không có row context. Đó chính là lý do SUM(A * B) báo lỗi: bên trong SUM không có khái niệm dòng nào cả. Nếu bạn còn thấy phần này mơ hồ, bài measure và calculated column nói kỹ hơn về row context và filter context.
Bốn tình huống bắt buộc dùng SUMX
1. Mô hình không có cột kết quả
Trường hợp kinh điển ở đầu bài. Bảng chỉ có đơn giá và số lượng, cần tổng thành tiền. Dùng SUMX là xong, không phải thêm cột nào vào file.
2. Phép tính cần lấy dữ liệu từ bảng khác
Bảng chi tiết bán hàng thường chỉ lưu mã sản phẩm và số lượng, còn đơn giá niêm yết nằm ở bảng Sản phẩm. Khi đó biểu thức bên trong SUMX cần RELATED để với sang bảng bên kia:
Doanh thu niêm yết = SUMX(ChiTietBan, ChiTietBan[SoLuong] * RELATED(SanPham[GiaNiemYet]))
RELATED chỉ chạy được khi đang có row context, nên nó gần như luôn xuất hiện bên trong một hàm iterator, và luôn đi theo chiều từ bảng nhiều sang bảng một.
3. Mỗi dòng có một hệ số riêng
Hóa đơn ngoại tệ mỗi dòng một tỷ giá, mỗi dòng một tỷ lệ chiết khấu, mỗi hợp đồng một tỷ lệ hoa hồng. Những bài toán này không thể quy về "cộng một cột" được, vì phép nhân phải xảy ra trước phép cộng.
Nhân tổng với tỷ giá bình quân rồi coi là xong là chỗ sai kinh điển. Tổng tiền quy đổi phải là tổng của từng dòng đã quy đổi, không phải tổng chưa quy đổi nhân với một tỷ giá đại diện.
4. Cần lọc theo điều kiện tính ở từng dòng
Ví dụ chỉ tính doanh thu của những dòng có thành tiền từ 10 triệu trở lên, trong khi cột thành tiền không tồn tại:
Doanh thu đơn lớn = SUMX(FILTER(BanHang, BanHang[DonGia] * BanHang[SoLuong] >= 10000000), BanHang[DonGia] * BanHang[SoLuong])
Ba chỗ ra số sai nhiều nhất
Lấy bình quân của cột thay vì bình quân thật
Đây là lỗi âm thầm nhất, cùng họ với lỗi tính tỷ lệ trên từng dòng rồi lấy trung bình.
Cần đơn giá bình quân, nhiều người viết AVERAGE(BanHang[DonGia]). Kết quả là bình quân của các đơn giá, coi một dòng bán 2 cái và một dòng bán 2.000 cái nặng như nhau. Con số đúng phải là tổng tiền chia tổng số lượng:
Đơn giá bình quân = DIVIDE(SUMX(BanHang, BanHang[DonGia] * BanHang[SoLuong]), SUM(BanHang[SoLuong]))
Cùng nguyên tắc đó, AVERAGEX cũng chỉ nên dùng khi bạn thật sự muốn bình quân theo dòng, chứ không phải để thay cho một phép chia hai tổng.
Dùng SUMX trong khi SUM là đủ
Chiều ngược lại cũng có hại. Nếu cột ThanhTien đã tồn tại và bạn vẫn viết SUMX(BanHang, BanHang[ThanhTien]), kết quả không sai nhưng bạn bắt máy đi duyệt từng dòng cho một việc mà nó có cách làm nhanh hơn nhiều.
Với vài chục nghìn dòng thì không ai nhận ra. Với bảng vài triệu dòng và một trang báo cáo có mười biểu đồ, khác biệt hiện ra thành mấy giây chờ mỗi lần bấm slicer. Nguyên tắc: có cột sẵn thì SUM, phải tính mới thì SUMX.
Đưa nhầm bảng vào tham số thứ nhất
SUMX duyệt đúng cái bảng bạn đưa vào. Nếu biểu thức của bạn dùng cột của bảng Chi tiết mà bạn lại đưa bảng Sản phẩm vào duyệt, Power BI vẫn chạy nhưng cho ra một con số vô nghĩa, thường là nhỏ hơn hoặc lớn hơn hẳn thực tế.
Mẹo tự kiểm: đọc to công thức thành một câu tiếng Việt. "Duyệt từng dòng của bảng chi tiết bán hàng, ở mỗi dòng lấy số lượng nhân đơn giá, rồi cộng lại." Nếu câu đó nghe không xuôi, công thức đang sai chỗ nào đó.
Đừng lạm dụng: nhiều việc nên làm sớm hơn
SUMX rất mạnh, nhưng không phải cái gì cũng nên giải bằng DAX. Nếu cột Thành tiền là một cột cố định, không phụ thuộc vào bộ lọc người xem, và bạn cần nó để lọc hoặc xếp hạng, hãy tạo nó ngay từ tầng Power Query khi nạp dữ liệu. Cột sinh ra ở đó đi qua đúng cơ chế nén của mô hình nên gọn hơn.
Quy tắc chung trong nghề: việc gì làm được ở tầng sớm hơn thì làm ở tầng đó. Power Query lo dọn dẹp và tính cột cố định, DAX lo những con số phải đổi theo bộ lọc. Nếu bạn chưa quen tầng Power Query, bài Power Query cho kế toán cho thấy những việc nên đẩy về đó.
Câu hỏi thường gặp
SUMX có làm báo cáo chậm không?
Có, nếu bảng lớn và biểu thức phức tạp, vì máy phải duyệt qua từng dòng. Nhưng SUMX trên một bảng vài triệu dòng với phép nhân đơn giản thường vẫn nhanh hơn nhiều so với việc thêm một calculated column nặng vào mô hình. Chỉ nên lo về hiệu năng khi bạn lồng nhiều iterator vào nhau hoặc gọi hàm phức tạp bên trong.
Vì sao SUMX của tôi trả về cùng một số ở mọi dòng?
Gần như luôn do thiếu quan hệ giữa bảng đang hiển thị trên báo cáo và bảng mà SUMX đang duyệt, nên bộ lọc của từng dòng không truyền được sang. Kiểm tra sơ đồ quan hệ trong Model view trước khi nghi ngờ công thức.
Khi nào dùng AVERAGEX thay vì AVERAGE?
Dùng AVERAGEX khi thứ cần lấy bình quân chưa tồn tại thành cột, hoặc khi bạn muốn bình quân theo một nhóm chứ không theo dòng, ví dụ doanh thu bình quân mỗi hóa đơn. Còn nếu chỉ muốn chia hai tổng cho nhau, hãy dùng DIVIDE với hai measure, đừng dùng AVERAGE.
SUMX kết hợp được với các hàm thời gian không?
Được, và rất hay dùng. Bạn có thể bọc SUMX bên trong CALCULATE cùng các hàm thời gian để tính lũy kế hoặc so cùng kỳ. Cách dùng những hàm đó nằm trong bài Time Intelligence trong DAX.
Hiểu iterator là mở được cả nhóm hàm
Phân biệt SUM với SUMX nghe như một chi tiết cú pháp nhỏ, nhưng nó là cánh cửa vào cách DAX suy nghĩ. Nắm được row context rồi thì AVERAGEX, MAXX, RANKX hay CONCATENATEX đều là cùng một cơ chế, bạn không phải học lại từng hàm.
Muốn thấy những nguyên tắc này nằm trong một mô hình hoàn chỉnh thay vì ví dụ rời rạc, bạn có thể xem các báo cáo phân tích bán hàng và những bộ báo cáo Power BI mẫu của EzTech, tất cả đều xem demo trực tiếp. Còn nếu muốn đi bài bản từ mô hình dữ liệu đến DAX rồi dựng báo cáo quản trị hoàn chỉnh, khóa DATA BUSINESS đi đúng lộ trình đó. Chưa rõ nên bắt đầu từ đâu, bạn cứ liên hệ với đội ngũ EzTech.