CodeGym /课程 /SQL SELF /用窗口函数计算累计和: SUM()、 AVG()

用窗口函数计算累计和: SUM()、 AVG()

SQL SELF
第 29 级, 课程 4
可用

想象一下:你在关注你公司的收入、网店的销售,或者只是分析自己一年的花销。你不光想看到每个月的收入或支出,还想明白它们是怎么一个月一个月累积起来的。

普通的聚合函数(GROUP BY)帮不上忙——它们会把数据分组,每组只返回一行。可如果你想看到每个月并且还要算累计和呢?这时候就得用 SUM() 搭配窗口函数了。

用窗口函数算累计和的基础

窗口函数让你可以在窗口范围内做聚合操作。这样我们就能在每一行上累加数值,但又不会把其他行删掉。再也不用为 GROUP BY 牺牲数据啦!

SUM() 配合窗口函数的语法

这是用来算累计和的基本模板:

SELECT
    column_name,
    SUM(column_name) OVER (PARTITION BY partition_column ORDER BY order_column) AS cumulative_sum
FROM 
    table_name;

这里:

  • SUM(column_name) —— 累加数值。
  • OVER() —— 定义窗口范围。
  • PARTITION BY —— 按组分区(可选)。
  • ORDER BY —— 定义窗口内的行顺序。

例子:每月累计收入

假设有一张你的收入表:

月份 收入
2023-01 1000
2023-02 1500
2023-03 2000

我们想看到每个月的收入和累计总和。来写个 SQL 查询:

SELECT
    月份,
    收入,
    SUM(收入) OVER (ORDER BY 月份) AS 累计收入
FROM 
    收入表;

结果:

月份 收入 累计收入
2023-01 1000 1000
2023-02 1500 2500
2023-03 2000 4500

发生了什么:

  1. ORDER BY 月份 在 OVER() 里告诉 PostgreSQL 要按时间顺序处理行。
  2. 每一行的累计和都是把所有之前的行(包括当前行)都加起来。

仔细想想这里的逻辑。第一行 SUM() 只算第一行,第二行算前两行,第三行算前三行。所以月份排序很重要!

例子:分地区累计收入

如果你有一张按地区分的销售表,部分数据可能是这样的:

地区 月份 收入
北方 2023-01 1000
北方 2023-02 1500
南方 2023-01 2000
南方 2023-02 2500

现在我们想分别算每个地区的累计收入:

SELECT
    地区,
    月份,
    收入,
    SUM(收入) OVER (PARTITION BY 地区 ORDER BY 月份) AS 累计收入
FROM 
    销售表;

结果会是这样:

地区 月份 收入 累计收入
北方 2023-01 1000 1000
北方 2023-02 1500 2500
南方 2023-01 2000 2000
南方 2023-02 2500 4500

现在每个地区都单独分析(PARTITION BY 地区),但每个地区内部还是按时间排序(ORDER BY 月份)。

滑动平均(AVG())

OK,累计和很酷,但如果你想分析最近 3 个月的趋势呢?这时候滑动平均就派上用场了。

例子:收入滑动平均

我们还是用 收入表,数据如下:

月份 收入
2023-01 1000
2023-02 1500
2023-03 2000
2023-04 2500

计算 3 个月滑动平均的查询:

SELECT
    月份,
    收入,
    AVG(收入) OVER (
        ORDER BY 月份 
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) AS 滑动平均
FROM 
    收入表;

结果:

月份 收入 滑动平均
2023-01 1000 1000
2023-02 1500 1250
2023-03 2000 1500
2023-04 2500 2000

解释:

  1. ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 告诉 PostgreSQL 取当前行和前两行来算平均。
  2. 所以每个月都能看到最近 3 个月的平均收入。

也就是说,每一行都用 3 行(当前+前两行)做窗口,然后算平均。超级方便。

ORDER BY 的作用和影响

窗口函数很依赖行的顺序。如果顺序错了(或者根本没指定),结果可能会很奇怪。

例子:没写 ORDER BY 的错误

如果我们把 OVER() 里的 ORDER BY 去掉,累计和就会变成每行都是所有收入的总和:

SELECT
    月份,
    收入,
    SUM(收入) OVER () AS 错误累计和
FROM 
    收入表;

结果:

月份 收入 错误累计和
2023-01 1000 7000
2023-02 1500 7000
2023-03 2000 7000
2023-04 2500 7000

行没排序,函数就直接把所有行加起来,每行都一样,根本不是累计和。

真实用法场景

收入分析:

  • 累计和能帮你追踪公司销售或收入的增长。
  • 滑动平均能让你看到“干净”的趋势,去掉噪音。

金融建模:

银行和金融公司用窗口函数分析还款、负债增长等各种指标。

时间序列分析:

像在线用户数、页面浏览量、营收这些时间数据,用 SUM() 和 AVG() 分析最合适不过了。

2
任务
SQL SELF, 第 29 级, 课程 4
已锁定
最近3个月的滑动平均值
最近3个月的滑动平均值
1
调查/小测验
窗口函数第 29 级,课程 4
不可用
窗口函数
窗口函数
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION