【PGCCC】使用 Postgres 进行数据分析的窗口函数

SQL 在处理单行数据时,甚至在聚合多行数据时都很有意义。但是,当您想比较已计算的行之间的数据时会发生什么?或者创建数据组并进行查询?输入窗口函数。

窗口函数往往会让人感到困惑 - 但它们是 SQL 中用于数据分析的非常棒的工具。最好的部分是,您不需要图表、花哨的 BI 工具或 AI 即可为利益相关者获取一些可操作且有用的数据。窗口函数可让您快速:

  • 计算累计总数
  • 提供数据组/分区的汇总统计信息
  • 创建排名
  • 执行滞后/超前分析,即将两组独立的数据相互比较
  • 计算移动/滚动平均值

本文将通过简单的电子商务数据架构,演示各种窗口函数及其实际应用。

什么是窗口函数?

Window 函数的部分OVER是创建窗口。令人讨厌的是,window 这个词在任何函数中都没有出现。通常,OVER 部分由另一个函数(聚合函数或数学函数)开头。通常还有一个框架,用于指定您正在查看的行ROWS BETWEEN 6 PRECEDING AND CURRENT ROW。

窗口函数 vs where 子句

窗口函数乍一看有点像 where子句,因为它们查看的是一组数据。但它们确实不同。窗口函数更适合于需要查看多组数据或多组数据的情况。有些情况下您可以使用其中任何一种。一般来说:

当您需要根据条件过滤行时使用WHERE子句。

当您需要对过滤后剩余的行执行计算,而不从结果集中删除任何行时,请使用窗口函数。

窗口函数的实际应用

1.累计

这是一个简单的入门步骤。让我们请求订单、客户数据、订单总额,然后是订单的累计总额。这将向我们显示某个日期范围内的订单总额。

sql 复制代码
SELECT
    SUM(total_amount) OVER (ORDER BY order_date) AS running_total,
    order_date,
    order_id,
    customer_id,
    total_amount
FROM
    orders
ORDER BY
    order_date;
sql 复制代码
 running_total |     order_date      | order_id | customer_id | total_amount
---------------+---------------------+----------+-------------+--------------
        349.98 | 2024-08-21 10:00:00 |       21 |           1 |       349.98
       1249.96 | 2024-08-22 11:30:00 |       22 |           2 |       899.98
       1284.94 | 2024-08-23 09:15:00 |       23 |           3 |        34.98
       1374.93 | 2024-08-24 14:45:00 |       24 |           4 |        89.99
       1524.92 | 2024-08-25 08:25:00 |       25 |           5 |       149.99
       1589.90 | 2024-08-26 12:05:00 |       26 |           6 |        64.98

这里发生的事情是,每个数据帧都是现有行加上之前的行。这种计算一次只进行一个切片,您可能在文档中看到它被称为虚拟表。下面是一个图表,可以让您大致了解每个数据帧是如何成为一组行的,这些行由 函数聚合而成SUM OVER。

2.第一个值和最后一个值

窗口函数可以查看数据组,因此说出特定的客户 ID 并为您提供一些信息,例如他们的第一笔和最后一笔订单、总额以及最近 10 笔订单的信息。

sql 复制代码
SELECT
    FIRST_VALUE(o.order_date) OVER (PARTITION BY o.customer_id ORDER BY o.order_date) AS first_order_date,
    LAST_VALUE(o.order_date) OVER (PARTITION BY o.customer_id ORDER BY o.order_date) AS last_order_date,
    o.order_id,
    o.customer_id,
    o.order_date,
    o.total_amount
FROM
    orders o
ORDER BY
    o.order_date DESC;
sql 复制代码
 first_order_date   |   last_order_date   | order_id | customer_id |     order_date      | total_amount
---------------------+---------------------+----------+-------------+---------------------+--------------
 2024-08-30 17:50:00 | 2024-09-19 18:50:00 |       50 |          10 | 2024-09-19 18:50:00 |       149.98
 2024-08-29 13:10:00 | 2024-09-18 14:10:00 |       49 |           9 | 2024-09-18 14:10:00 |       199.98
 2024-08-28 10:20:00 | 2024-09-17 11:20:00 |       48 |           8 | 2024-09-17 11:20:00 |       139.99
 2024-08-27 16:35:00 | 2024-09-16 17:35:00 |       47 |           7 | 2024-09-16 17:35:00 |       249.98
 2024-08-26 12:05:00 | 2024-09-15 13:05:00 |       46 |           6 | 2024-09-15 13:05:00 |        89.98

3.使用 date_trunc GROUP BY CTE 和窗口函数

date_trunc是一个非常方便的 Postgres 函数,可以汇总时间单位、小时、天、周、月。与GROUP BYCTE 中的结合使用时,您可以按日、月、周、年等创建非常简单的汇总统计数据。

当您将 date_trunc GROUP BY 分区与窗口函数结合使用时,会发生一些非常神奇的事情,您可以直接从数据库中获取现成的汇总统计数据。在我看来,这是 Postgres 窗口函数最强大的功能之一,它真正让您更上一层楼。

以下是一个以 CTE 开头的示例查询,调用 date_trunc 按每日总数对订单进行汇总。查询的第二部分是窗口函数,按降序排列销售额,并按销售额最高的日期进行排序。

sql 复制代码
WITH DailySales AS (
    SELECT
        date_trunc('day', o.order_date) AS sales_date,
        SUM(o.total_amount) AS daily_total_sales
    FROM
        orders o
    GROUP BY
        date_trunc('day', o.order_date)
)
SELECT
    sales_date,
    daily_total_sales,
    RANK() OVER (
        ORDER BY daily_total_sales DESC
    ) AS sales_rank
FROM
    DailySales
ORDER BY
    sales_rank;
sql 复制代码
  sales_date      | daily_total_sales | sales_rank
---------------------+-------------------+------------
 2024-09-02 00:00:00 |           2419.97 |          1
 2024-09-01 00:00:00 |           1679.94 |          2
 2024-08-22 00:00:00 |            899.98 |          3
 2024-09-07 00:00:00 |            699.95 |          4
 2024-09-10 00:00:00 |            659.96 |          5
 2024-09-09 00:00:00 |            499.94 |          6
 2024-09-06 00:00:00 |            409.94 |          7
 2024-08-30 00:00:00 |            349.99 |          8

RANK我应该注意到,这使用了窗口函数中一个非常有用的数学函数。

4.滞后分析 (LAG)

让我们使用 date_trunc CTE 做更多事情。现在我们知道我们有按天划分的数据,我们可以使用窗口函数来计算这些组之间的变化。例如,我们可以查看与前一天相比的销售额差异。在此示例中,LAG查看销售日期并与前一天进行比较。

sql 复制代码
WITH DailySales AS (
    SELECT
        date_trunc('day', o.order_date) AS sales_date,
        SUM(o.total_amount) AS daily_total_sales
    FROM
        orders o
    GROUP BY
        date_trunc('day', o.order_date)
)
SELECT
    sales_date,
    daily_total_sales,
    LAG(daily_total_sales) OVER (
        ORDER BY sales_date
    ) AS previous_day_sales,
    daily_total_sales - LAG(daily_total_sales) OVER (
        ORDER BY sales_date
    ) AS sales_difference
FROM
    DailySales
ORDER BY
    sales_date;
sql 复制代码
     sales_date      | daily_total_sales | previous_day_sales | sales_difference
---------------------+-------------------+--------------------+------------------
 2024-08-21 00:00:00 |            349.98 |                    |
 2024-08-22 00:00:00 |            899.98 |             349.98 |           550.00
 2024-08-23 00:00:00 |             34.98 |             899.98 |          -865.00
 2024-08-24 00:00:00 |             89.99 |              34.98 |            55.01
 2024-08-25 00:00:00 |            149.99 |              89.99 |            60.00
 2024-08-26 00:00:00 |             64.98 |             149.99 |           -85.01

LEAD以相同的方式工作,在数据集中向前看。 5.计算滚动平均值

使用同一天的组,我们还可以计算出滚动平均值。该函数接受7 天的滚动销售平均值作为AVG输入。ROWS BETWEEN 6 PRECEDING AND CURRENT ROW

sql 复制代码
WITH DailySales AS (
    SELECT
        date_trunc('day', o.order_date) AS sales_date,
        SUM(o.total_amount) AS daily_total_sales
    FROM
        orders o
    GROUP BY
        date_trunc('day', o.order_date)
)
SELECT
    sales_date,
    daily_total_sales,
    AVG(daily_total_sales) OVER (
        ORDER BY sales_date
        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
    ) AS rolling_average_7_days
FROM
    DailySales
ORDER BY
    sales_date
LIMIT 10;
sql 复制代码
     sales_date      | daily_total_sales | rolling_average_7_days
---------------------+-------------------+------------------------
 2024-08-21 00:00:00 |            349.98 |   349.9800000000000000
 2024-08-22 00:00:00 |            899.98 |   624.9800000000000000
 2024-08-23 00:00:00 |             34.98 |   428.3133333333333333
 2024-08-24 00:00:00 |             89.99 |   343.7325000000000000
 2024-08-25 00:00:00 |            149.99 |   304.9840000000000000
 2024-08-26 00:00:00 |             64.98 |   264.9833333333333333
 2024-08-27 00:00:00 |            249.98 |   262.8400000000000000
 2024-08-28 00:00:00 |            129.99 |   231.4128571428571429
 2024-08-29 00:00:00 |            179.98 |   128.5557142857142857
 2024-08-30 00:00:00 |            349.99 |   173.5571428571428571
(10 rows)

小结

窗口函数是 SQL 中功能强大且灵活的工具,尤其适用于复杂的数据分析任务。通过使用这些函数,您可以轻松执行数据的累计计算、滞后分析、排名生成和滚动统计,而无需借助复杂的外部工具。充分掌握这些函数的使用,将极大地提升您在 SQL 数据分析中的效率和能力。

#PG证书#PG考试#postgresql培训#postgresql考试#postgresql认证

相关推荐
Watermelo61720 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
古希腊掌管学习的神1 小时前
[搜广推]王树森推荐系统——矩阵补充&最近邻查找
python·算法·机器学习·矩阵
TGB-Earnest2 小时前
【py脚本+logstash+es实现自动化检测工具】
大数据·elasticsearch·自动化
martian6652 小时前
【人工智能数学基础篇】——深入详解多变量微积分:在机器学习模型中优化损失函数时应用
人工智能·机器学习·微积分·数学基础
人机与认知实验室2 小时前
人、机、环境中各有其神经网络系统
人工智能·深度学习·神经网络·机器学习
大圣数据星球4 小时前
Fluss 写入数据湖实战
大数据·设计模式·flink
suweijie7684 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
古希腊掌管学习的神6 小时前
[机器学习]XGBoost(3)——确定树的结构
人工智能·机器学习
海棠AI实验室9 小时前
AI的进阶之路:从机器学习到深度学习的演变(一)
人工智能·深度学习·机器学习
Data跳动9 小时前
Spark内存都消耗在哪里了?
大数据·分布式·spark