MySQL窗口函数中的Frame(三)

本文深入解析MySQL中的窗口函数,包括其概念、语法及限制。详细介绍了如何通过定义frame计算累计金额与滚动平均值,展示了frame_clause的语法结构,并提供了具体的查询示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

12.21.1 Window Function Descriptions

12.21.2 Window Function Concepts and Syntax

12.21.3 Window Function Frame Specification

12.21.4 Named Windows

12.21.5 Window Function Restrictions

 

Frame定义

MySQL中的窗口定义是中包含一个frame定义,frame是当前窗口中的一个子数据集,frame子句便定义了如何定义子数据集(frame可以认为是窗口数据中的一个子数据集,数据帧)。

Frame的范围是根据当前row进行确定的,frame可以使用的场景:

1:通过定义frame计算截止每一订单时刻的总共金额。

2:还可以借助定义frame进行滚动计算平均值。

具体例子如下:

mysql> SELECT
         time, subject, val,
         SUM(val) OVER (PARTITION BY subject ORDER BY time
                        ROWS UNBOUNDED PRECEDING)
           AS running_total,
         AVG(val) OVER (PARTITION BY subject ORDER BY time
                        ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
           AS running_average
       FROM observations;
+----------+---------+------+---------------+-----------------+
| time     | subject | val  | running_total | running_average |
+----------+---------+------+---------------+-----------------+
| 07:00:00 | st113   |   10 |            10 |          9.5000 |
| 07:15:00 | st113   |    9 |            19 |         14.6667 |
| 07:30:00 | st113   |   25 |            44 |         18.0000 |
| 07:45:00 | st113   |   20 |            64 |         22.5000 |
| 07:00:00 | xh458   |    0 |             0 |          5.0000 |
| 07:15:00 | xh458   |   10 |            10 |          5.0000 |
| 07:30:00 | xh458   |    5 |            15 |         15.0000 |
| 07:45:00 | xh458   |   30 |            45 |         20.0000 |
| 08:00:00 | xh458   |   25 |            70 |         27.5000 |
+----------+---------+------+---------------+-----------------+

分析1:

按照subject分类计算每一个订单时刻的订单金额:

SUM(val) OVER (PARTITION BY subject ORDER BY time ROWS UNBOUNDED PRECEDING) AS running_total

ROWS UNBOUNDED PRECEDING为frame的定义,含义是每次计算当前行到第一行的所有val的和,例如 :第三行running_total=44的计算为10+9+25。

分析2:

指定frame大小为3进行滚定计算平均值:

AVG(val) OVER (PARTITION BY subject ORDER BY time ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS running_average

ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS running_average为frame的定义,对当前行的前一行,当前行以及当前行的后一行三行进行计算平均值,对于第一行与最后一行的处理会使用两行进行平均值。(这就是一个滚动窗口,窗口大小为3);例如第三行的running_average=18计算过程为:(9+25+20)/3=18 。

 

Frame语法定义

frame_clause:
    frame_units frame_extent

frame_units:
    {ROWS | RANGE}

frame的范围有两个单位,分别是ROWS与RANGE,分别是使用行确定frame,另外一个就是使用数值范围。

frame_extent:
    {frame_start | frame_between}

frame_between:
    BETWEEN frame_start AND frame_end

frame_start, frame_end: {
    CURRENT ROW
  | UNBOUNDED PRECEDING
  | UNBOUNDED FOLLOWING
  | expr PRECEDING
  | expr FOLLOWING
}

可以使用BETWEEN定义frame的开始与结束范围,frame_start 必须大于frame_end. 范围定义关键字含义:

  • CURRENT ROW: For ROWS, the bound is the current row. For RANGE, the bound is the peers of the current row.

  • UNBOUNDED PRECEDING: The bound is the first partition row.

  • UNBOUNDED FOLLOWING: The bound is the last partition row.

  • expr PRECEDING: For ROWS, the bound is expr rows before the current row. For RANGE, the bound is the rows with values equal to the current row value minus expr; if the current row value is NULL, the bound is the peers of the row.

  • expr FOLLOWING: For ROWS, the bound is expr rows after the current row. For RANGE, the bound is the rows with values equal to the current row value plus expr; if the current row value is NULL, the bound is the peers of the row.

 

示例:

数据集:

查询语句:

select *, sum(cnt)  over w as from_7_days_ago_to_current_cnt
from open_id_to_pin
    window w as (partition by open_id order by expire_time desc RANGE between INTERVAL 7 DAY PRECEDING and current row );

解读:

根据open_id划分窗口之后按照expire_time排序,frame的范围确定是根据当前行的expire_time开始到当前expire_time-7天作为结束的frame,查询结果为:

 

### MySQL 窗口函数简介 窗口函数是一种强大的 SQL 工具,允许在查询中执行复杂的计算而不影响原始数据集的行数。它通过 `OVER()` 子句定义一个逻辑分区或顺序来操作数据[^1]。 #### 基本语法结构 窗口函数的基本语法如下: ```sql function_name(expression) OVER ( [PARTITION BY partition_expression] [ORDER BY sort_expression] [frame_clause] ) ``` - **`function_name`**: 支持多种内置聚合函数(如 `SUM`, `AVG`, `COUNT`, `MAX`, `MIN`)以及排名函数(如 `ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`)。 - **`PARTITION BY`**: 定义分组逻辑,类似于 `GROUP BY` 的作用,但它不会减少返回的结果行数。 - **`ORDER BY`**: 指定每一分区内的排序方式。 - **`frame_clause`**: 可选部分,用于进一步限定窗口范围,例如指定当前行之前的若干行作为计算依据。 --- ### 示例:使用窗口函数进行数据分析 假设有一个名为 `sales` 的表,记录了销售员及其销售额的信息: | id | salesperson | amount | |----|-------------|--------| | 1 | Alice | 200 | | 2 | Bob | 300 | | 3 | Alice | 400 | | 4 | Charlie | 500 | #### 计算累计总和 如果想按销售人员统计其累积销售额,则可以使用以下语句: ```sql SELECT salesperson, amount, SUM(amount) OVER (PARTITION BY salesperson ORDER BY id) AS cumulative_sum FROM sales; ``` 此查询会针对每位销售人员分别计算累加金额,并按照 `id` 排序[^2]。 #### 添加排名功能 为了给每个销售人员分配名次,可引入排名函数 `ROW_NUMBER()` 或者 `RANK()`: ```sql SELECT salesperson, amount, RANK() OVER(ORDER BY amount DESC) as rank_position FROM sales; ``` 上述代码片段展示了如何基于销售额大小为所有记录赋予相应等级位置[^3]。 --- ### 注意事项 尽管窗口函数非常强大,在实际应用过程中仍需注意性能调优问题。对于大数据量场景下的复杂运算尤其如此;合理设计索引并测试不同实现方案有助于提升效率[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

javartisan

对您有帮助,欢迎老板赐一杯奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值