Lúc đầu nhìn vào thì có vẻ SQL đã có đủ mọi thứ để phân tích dữ liệu rồi: GROUP BY, aggregate, subquery... Nhưng đó chỉ là khởi đầu thôi. Chào mừng đến với thế giới của window functions — công cụ cực mạnh cho phép làm việc với dữ liệu từng dòng mà vẫn giữ nguyên toàn bộ context.
Window functions cho phép thực hiện các phép tính — tổng, trung bình, rank và nhiều thứ khác — trên “cửa sổ” các dòng mà không cần gộp dữ liệu lại. Điều này có nghĩa là khác với các hàm aggregate thông thường (SUM(), AVG(), COUNT()), bạn sẽ nhận được cả kết quả lẫn chi tiết trên từng dòng.
Hãy tưởng tượng bạn muốn tính tổng thu nhập tích lũy theo từng đơn hàng. Nếu dùng GROUP BY thì bạn sẽ mất hết thông tin từng đơn — chỉ còn lại tổng thôi. Nhưng với window function, bạn có thể thêm kết quả trực tiếp vào từng dòng mà không mất gì cả.
Window functions cực kỳ tiện vì nó không phá hủy dữ liệu: mỗi dòng vẫn giữ nguyên, còn kết quả tính toán thì chỉ được thêm vào cột mới thôi. Nhờ vậy bạn có thể làm phân tích phức tạp mà không cần subquery hay mấy cấu trúc lằng nhằng — tất cả nằm gọn trong một query. Loại function này cực hợp cho các bài toán như ranking, tính moving average hoặc so sánh giá trị giữa các dòng. Code vẫn dễ đọc, kết quả thì chuẩn xác.
Khi nào nó đặc biệt hữu ích:
- Xếp hạng nhân viên, seller, sản phẩm — ai đang ở vị trí nào.
- Dãy thời gian — cái gì thay đổi theo ngày hoặc tuần.
- Bán hàng và tài chính — tích lũy được bao nhiêu ở mỗi bước, đơn hàng nào cao hơn trung bình, ai nằm trong top 25%.
Window functions dùng ở đâu
Bất cứ lĩnh vực nào mà context quan trọng, không chỉ là kết quả cuối:
- báo cáo bán hàng;
- phân tích hành vi khách hàng;
- vẽ biểu đồ với các chỉ số tích lũy;
- phân đoạn dữ liệu (ví dụ theo quartile);
- tính độ lệch và xu hướng.
Nó thực sự là bảo bối cho mấy bạn analyst làm SQL mỗi ngày. Cùng xem vài ví dụ thực tế nơi window functions có thể cứu bạn khỏi đau đầu.
Ví dụ 1: Xếp hạng dữ liệu
Giả sử bạn có danh sách sinh viên với điểm thi của họ. Bạn muốn gán cho mỗi sinh viên vị trí của họ trong lớp. Dùng window functions thì dễ như ăn kẹo luôn. Ví dụ, các hàm RANK() hoặc ROW_NUMBER() sẽ giúp bạn làm việc này.
Ví dụ 2: Phân tích dữ liệu thời gian
Giả sử bạn cần xem thu nhập của công ty thay đổi theo từng tháng như thế nào? Bạn cần tổng thu nhập tích lũy. Dùng window function SUM() với cửa sổ phù hợp là bạn có ngay kết quả.
Ví dụ 3: Quartile và chia nhóm
Muốn chia dữ liệu thành các nhóm bằng nhau (ví dụ theo thu nhập) để phân đoạn khách hàng? Lúc này function NTILE() sẽ cứu bạn. Cùng xem ai trong top 25% khách hàng, ai ở cuối bảng xếp hạng nhé.
Trông nó như thế nào?
Window function chỉ đơn giản là thêm kết quả vào tập dữ liệu cuối cùng:
SELECT
student_id,
grade,
RANK() OVER (ORDER BY grade DESC) AS rank
FROM
students;
Ở đây bạn sẽ có bảng mà mỗi sinh viên đều có rank riêng theo điểm số của mình.
So sánh đơn giản
Hãy tưởng tượng bạn đang chạy bộ với nhóm bạn. Mỗi người chạy với tốc độ riêng, nhưng bạn muốn biết mình đang ở vị trí nào trong cuộc đua ngay lúc này. Thay vì dừng tất cả lại để lập bảng xếp hạng (kiểu như GROUP BY), bạn chỉ cần nhìn quanh và xác định thứ hạng hiện tại của mình.
Đó chính là window function: nó không dừng cuộc đua, không chia nhóm mọi người — nó chỉ thêm thông tin vào, giữ nguyên chuyển động và chi tiết. Ai cũng tiếp tục chạy, nhưng giờ bạn có thêm phân tích — ví dụ có bao nhiêu người phía trước, tốc độ của bạn so với trung bình, v.v.
Lợi thế so với cách truyền thống
Xem thử một bài toán kinh điển: xếp hạng seller theo doanh thu. Có hai cách:
Không dùng window functions. Bạn phải viết subquery hoặc thậm chí nhiều subquery, đầu tiên để sort dữ liệu, sau đó đánh số thứ tự. Vừa dài vừa khó đọc.
Dùng window functions. Chỉ một query với cú pháp đẹp và dễ hiểu, kết quả có ngay. Ví dụ:
SELECT
seller_id,
revenue,
RANK() OVER (PARTITION BY region ORDER BY revenue DESC) AS rank_in_region
FROM
sales;
Query này sẽ chia seller theo từng region và đánh số thứ tự giảm dần theo doanh thu.
Ví dụ thực tế
Giờ giả sử bạn là analyst và đang phân tích dữ liệu bán hàng. Bạn cần biết:
- tổng doanh thu từng tháng,
- doanh thu thay đổi thế nào so với tháng trước,
- xếp hạng các region theo tổng doanh thu.
Tất cả đều có thể làm bằng window functions, thậm chí chỉ trong một query. Nhưng đó là chủ đề cho các bài sau nhé.
Giờ thì, với kiến thức cơ bản về window functions, bạn đã sẵn sàng học cú pháp và thấy sức mạnh của các hàm ROW_NUMBER(), RANK(), DENSE_RANK() và NTILE(). Cùng sang bài tiếp theo nào!
GO TO FULL VERSION