CodeGym /課程 /SQL SELF /窗口函式 vs 聚合函式比較: GROUP BY vs PARTITIO...

窗口函式 vs 聚合函式比較: GROUP BY vs PARTITION BY

SQL SELF
等級 30 , 課堂 0
開放

乍看之下,窗口函式跟聚合函式好像都是拿來分析跟處理資料的工具。畢竟兩者都能做像是 sum、avg、排名這種計算。但我們來細看一下,實際上它們本質上有什麼差別。

聚合函式(GROUP BY

聚合函式的運作方式如下:

  • 它們會根據你指定的欄位把資料分組。
  • 分組之後,每一組只會剩下一列結果
  • 舉例:你想知道每個地區的總收入。
SELECT region, SUM(sales) AS total_sales
FROM sales_data
GROUP BY region;

特點:GROUP BY 會「壓縮」資料。如果你用了分組,屬於同一組的所有列都會消失——只剩下聚合的結果。

窗口函式(PARTITION BY

窗口函式則是這樣:

  • 會保留原本的資料結構(不會壓縮或讓列消失!)。
  • 可以在「窗口」——也就是邏輯上分開的分組裡做計算。

舉例:你想知道每個城市在它所屬地區的總銷售額佔比,但又想保留所有資料。

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

特點:用窗口函式不會刪掉任何列,只是把新的計算值加到每一列上。

範例:SUM() 搭配 GROUP BY vs SUM() 搭配 PARTITION BY

為了更清楚差異,我們來看 SUM() 在兩種情境下怎麼運作。假設我們有一張 sales_data 表長這樣:

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

GROUP BY 做加總

我們想知道每個地區的總銷售額:

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

結果會長這樣:

region total_sales
North 250
South 450

發生了什麼:資料根據 region 分組,每組被「壓縮」成一列,顯示銷售總和。

PARTITION BY 做加總

現在我們用窗口函式做一樣的事:

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

結果:

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

發生了什麼:PARTITION BY 沒有「壓縮」資料,而是在每個「窗口」(每個地區)裡計算總和,然後把結果加到每一列。

什麼時候該用 GROUP BY,什麼時候該用 PARTITION BY

GROUP BY適合做最終報表

GROUP BY 很適合你想要縮減資料量、只看分組結果的時候。像是:

  • 每個月的總銷售額。
  • 每個商品類別的訂單數。

範例:

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

PARTITION BY超適合分析跟細部觀察

PARTITION BY 適合你想保留所有資料列、又想對每一列多算點東西的時候。像是:

  • 算出每個商品在類別裡的銷售佔比。
  • 在每個分組裡給資料編號。

計算銷售佔比的範例:

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

範例:同時用多個窗口函式

窗口函式一大優點就是可以一次做很多計算。舉例:

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;

結果:

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

窗口函式比 GROUP BY 更強的地方

保留原始資料GROUP BY 會壓縮資料列,但窗口函式可以讓你保留原本的表格結構。

一個查詢多種計算: 你可以在同一個查詢裡用不同參數的 PARTITION BYORDER BY 做多種窗口函式計算,資料都還在。

分析超彈性: 窗口函式可以讓你根據需求做累積總和、排名、比例計算等等,超級彈性。

彈性範例

我們來組合幾個函式:

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;

結果:

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

限制跟常見錯誤

一個很常見的錯誤是想用 PARTITION BY 來「壓縮」資料。像是,應該這樣寫:

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

但有人會寫成這樣:

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

但這樣會回傳所有資料列,資料量一點都沒減少(有時候這不是你想要的)。

現在你一定知道什麼時候該用 GROUP BY,什麼時候該用窗口函式了。這就像選擇要用鐵鎚還是螺絲起子:兩個工具都能處理釘子……但方式不一樣啦。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION