CodeGym /Các khóa học /SQL SELF /So sánh window function với aggregate function: GR...

So sánh window function với aggregate function: GROUP BY vs PARTITION BY

SQL SELF
Mức độ , Bài học
Có sẵn

Nhìn sơ qua thì window function và aggregate function có vẻ giống nhau khi phân tích và xử lý dữ liệu. Cả hai đều thực hiện các phép tính như tổng, trung bình, xếp hạng v.v. Nhưng hãy cùng xem chúng khác nhau ở điểm nào nhé.

Aggregate function (GROUP BY)

Aggregate function hoạt động như sau:

  • Nó nhóm các dòng theo cột được chỉ định.
  • Sau khi nhóm, mỗi nhóm sẽ thành một dòng kết quả duy nhất.
  • Ví dụ: bạn muốn biết tổng doanh thu theo từng vùng.
SELECT region, SUM(sales) AS total_sales
FROM sales_data
GROUP BY region;

Đặc điểm: GROUP BY "nén" dữ liệu. Nếu bạn dùng group, tất cả các dòng trong cùng một nhóm sẽ biến mất — chỉ còn lại kết quả tổng hợp.

Window function (PARTITION BY)

Window function thì ngược lại:

  • Giữ nguyên cấu trúc dữ liệu gốc (không nén hay làm mất dòng nào hết!).
  • Có thể thực hiện phép tính trong từng "window" — nhóm dòng được chia logic.

Ví dụ: bạn muốn biết tỷ lệ doanh số của từng thành phố trong tổng doanh số của vùng, nhưng vẫn giữ nguyên tất cả dữ liệu.

SELECT
    region,
    city,
    sales,
    SUM(sales) OVER (PARTITION BY region) AS total_sales_by_region
FROM sales_data;

Đặc điểm: dùng window function không làm mất dòng nào, chỉ thêm giá trị tính toán mới vào từng dòng thôi.

Ví dụ: SUM() với GROUP BY vs SUM() với PARTITION BY

Để hiểu rõ hơn, cùng xem SUM() hoạt động thế nào ở cả hai trường hợp. Giả sử bạn có bảng sales_data như sau:

region city sales
North CityA 100
North CityB 150
South CityC 200
South CityD 250

Tính tổng bằng GROUP BY

Chúng ta muốn biết tổng doanh số theo từng vùng:

SELECT region, SUM(sales) AS total_sales
FROM sales_data
GROUP BY region;

Kết quả sẽ như sau:

region total_sales
North 250
South 450

Chuyện gì đã xảy ra: các dòng được nhóm theo region, và mỗi nhóm bị "nén" thành một dòng với tổng doanh số.

Tính tổng bằng PARTITION BY

Bây giờ làm tương tự với window function:

SELECT
    region,
    city,
    sales,
    SUM(sales) OVER (PARTITION BY region) AS total_sales_by_region
FROM sales_data;

Kết quả:

region city sales total_sales_by_region
North CityA 100 250
North CityB 150 250
South CityC 200 450
South CityD 250 450

Chuyện gì đã xảy ra: PARTITION BY không "nén" dòng nào. Thay vào đó nó tính tổng trong từng window (mỗi vùng là một window riêng).

Khi nào dùng GROUP BY và khi nào dùng PARTITION BY?

GROUP BY: hợp cho báo cáo tổng kết

GROUP BY hữu ích khi bạn muốn giảm lượng dữ liệu và lấy kết quả cuối cùng ở cấp nhóm. Ví dụ:

  • Tổng doanh số theo tháng.
  • Đếm số đơn hàng theo loại sản phẩm.

Ví dụ:

SELECT category, COUNT(*) AS total_orders
FROM orders
GROUP BY category;

PARTITION BY: chuẩn cho phân tích chi tiết

PARTITION BY hợp khi bạn cần giữ nguyên tất cả dòng dữ liệu và tính thêm gì đó cho từng dòng. Ví dụ:

  • Tính tỷ lệ doanh số của từng sản phẩm trong loại.
  • Đánh số dòng trong từng nhóm.

Ví dụ tính tỷ lệ doanh số:

SELECT
    category,
    product,
    sales,
    ROUND(
        (sales * 100.0) / SUM(sales) OVER (PARTITION BY category),
        2
    ) AS sales_percentage
FROM sales_data;

Ví dụ: dùng nhiều window function cùng lúc

Một ưu điểm của window function là bạn có thể dùng nhiều phép tính cùng lúc. Ví dụ:

SELECT
    region,
    city,
    sales,
    SUM(sales) OVER (PARTITION BY region) AS total_sales,
    RANK() OVER (PARTITION BY region ORDER BY sales DESC) AS sales_rank
FROM sales_data;

Kết quả:

region city sales total_sales sales_rank
North CityB 150 250 1
North CityA 100 250 2
South CityD 250 450 1
South CityC 200 450 2

Ưu điểm của window function so với GROUP BY

Giữ nguyên dữ liệu gốc: GROUP BY "nén" dòng, còn window function thì giữ nguyên cấu trúc bảng.

Nhiều phép tính trong một query: Bạn có thể dùng nhiều window function với các tham số PARTITION BYORDER BY khác nhau mà vẫn giữ dữ liệu.

Phân tích linh hoạt: Window function cho phép bạn tuỳ chỉnh phép tính theo ý muốn: tổng tích luỹ, xếp hạng, tính tỷ lệ và nhiều thứ khác.

Ví dụ về sự linh hoạt

Thử kết hợp nhiều function:

SELECT
    region,
    city,
    sales,
    SUM(sales) OVER (PARTITION BY region) AS total_sales,
    AVG(sales) OVER (PARTITION BY region) AS avg_sales,
    RANK() OVER (PARTITION BY region ORDER BY sales DESC) AS rank
FROM sales_data;

Kết quả:

region city sales total_sales avg_sales rank
North CityB 150 250 125.0 1
North CityA 100 250 125.0 2
South CityD 250 450 225.0 1
South CityC 200 450 225.0 2

Giới hạn và lỗi thường gặp

Một lỗi phổ biến là cố dùng PARTITION BY khi cần "nén" dữ liệu. Ví dụ, thay vì:

SELECT region, SUM(sales) AS total_sales
FROM sales_data
GROUP BY region;

Có bạn lại viết như này:

SELECT
    region,
    SUM(sales) OVER (PARTITION BY region) AS total_sales
FROM sales_data;

Nhưng cái này sẽ trả về tất cả các dòng, không giảm lượng dữ liệu (không phải lúc nào cũng đúng ý bạn muốn).

Bây giờ bạn đã biết rõ khi nào dùng GROUP BY, khi nào dùng window function. Nó giống như chọn giữa búa và tua vít: cả hai đều làm việc với đinh... nhưng theo cách khác nhau.

2
Nhiệm vụ
SQL SELF, mức độ, bài học
Đã khóa
Tổng doanh số theo vùng với việc giữ nguyên tất cả các dòng (`PARTITION BY`)
Tổng doanh số theo vùng với việc giữ nguyên tất cả các dòng (`PARTITION BY`)
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION