CodeGym /课程 /SQL SELF /用 PARTITION BY 把数据分组

用 PARTITION BY 把数据分组

SQL SELF
第 29 级, 课程 3
可用

想象一下,你在一家大餐厅当服务员(或者你喜欢咖啡的话,可以当 barista)。每天你都要统计一下今天收到的小费。但有个细节:餐厅分了好几个区域,你想知道每个区域的小费分别是多少。PARTITION BY 就是 SQL 用来“把餐厅分区”的工具。

正式点说,PARTITION BY 是在窗口函数里用来把表里的所有行分成不同的小组(或者说“分区”)。每个分区里,窗口函数会重新执行一次。就像你在每个“分区”里单独用一次函数一样。

例子:它怎么用

假设我们有个 sales 表,里面是销售数据:

region salesperson amount
North Alice 100
North Bob 200
South Alice 150
South Charlie 250

如果我们想算每个销售员赚了多少钱,但要按区域分别算,PARTITION BY 就是你要用的东西。

PARTITION BY 的语法

语法其实很简单:

窗口函数() OVER (PARTITION BY 列名_或_列名们)
  • 窗口函数() — 比如 SUM()、AVG()、ROW_NUMBER() 这些。
  • PARTITION BY 列名 — 指定要按哪个列来分组。
  • OVER() — 这个操作符告诉 SQL:“在这个窗口范围内做点啥”。

例子:分组求和

来算一下每个区域的销售总额:

SELECT
    region,
    salesperson,
    amount,
    SUM(amount) OVER (PARTITION BY region) AS total_sales_by_region
FROM sales;

结果会是这样:

region salesperson amount total_sales_by_region
North Alice 100 300
North Bob 200 300
South Alice 150 400
South Charlie 250 400

发生了啥?SQL 按 region(North 和 South)把行分组,然后对每组单独用 SUM()。所以,"North" 组里的每行总额一样,"South" 组也是一样。

PARTITION BY 的实际用法例子

来看看 PARTITION BY 在实际开发里怎么用。

例子 1:组内排名

假如我们想在每个区域里给销售员按销售额排个名。可以用 PARTITION BY 加 RANK():

SELECT
    region,
    salesperson,
    amount,
    RANK() OVER (PARTITION BY region ORDER BY amount DESC) AS rank_in_region
FROM sales;

结果:

region salesperson amount rank_in_region
North Bob 200 1
North Alice 100 2
South Charlie 250 1
South Alice 150 2

RANK() 会在每个 region 组里从 1 开始给行编号。注意,每组都是从 1 开始。

例子 2:和组内平均值对比

比如我们想看看每个销售员赚的和自己区域的平均比起来咋样。用 AVG():

SELECT
    region,
    salesperson,
    amount,
    AVG(amount) OVER (PARTITION BY region) AS avg_sales_by_region,
    amount - AVG(amount) OVER (PARTITION BY region) AS diff_from_avg
FROM sales;

结果:

region salesperson amount avg_sales_by_region diff_from_avg
North Alice 100 150 -50
North Bob 200 150 50
South Alice 150 200 -50
South Charlie 250 200 50

SQL 先按 region 分组,然后算每组的 AVG(amount),最后每行再算和平均的差值。

例子 3:组内行号

比如你想给每个区域里的交易编号。用 ROW_NUMBER():

SELECT
    region,
    salesperson,
    amount,
    ROW_NUMBER() OVER (PARTITION BY region ORDER BY amount DESC) AS row_number
FROM sales;

结果:

region salesperson amount row_number
North Bob 200 1
North Alice 100 2
South Charlie 250 1
South Alice 150 2

和 GROUP BY 的区别

很多人会把 PARTITION BY 和 GROUP BY 搞混。来对比一下:

GROUP BY

GROUP BY 会改变输出结构——它把表的行变成聚合结果。比如:

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

结果:

region total_sales
North 300
South 400

这里我们就看不到销售员的信息了,因为数据被聚合了。

PARTITION BY

PARTITION BY 则不会改变结构。每行都还在,只是多了按组算出来的值。也就是说,PARTITION BY 能聚合但不丢细节。

用 PARTITION BY 时常见的坑

坑 1:忘了 PARTITION BY

有时候你想分组,但忘了写 PARTITION BY。比如:

SELECT
    region,
    salesperson,
    amount,
    SUM(amount) OVER () AS total_sales
FROM sales;

结果:

region salesperson amount total_sales
North Alice 100 700
North Bob 200 700
South Alice 150 700
South Charlie 250 700

这里 SUM(amount) 是全表的总和,不是按区域分的。如果你想按区域分,记得加 PARTITION BY region。

坑 2:ORDER BY 顺序写错了

窗口里的行顺序对 RANK() 或 ROW_NUMBER() 这些函数很重要。用 OVER() 里的 ORDER BY 时要小心顺序。

2
任务
SQL SELF, 第 29 级, 课程 3
已锁定
按地区统计销售总额
按地区统计销售总额
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION