CodeGym /课程 /SQL SELF /窗口函数和聚合函数对比: GROUP BY vs PARTITION B...

窗口函数和聚合函数对比: 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 BY 和 ORDER 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,啥时候用窗口函数了。这就像选锤子还是螺丝刀:都能搞钉子……但用法不一样。

2
任务
SQL SELF, 第 30 级, 课程 0
已锁定
按区域保留所有行的销售总额(`PARTITION BY`)
按区域保留所有行的销售总额(`PARTITION BY`)
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION