SQL Window Function

本文介绍了SQL中的窗口函数,包括PARTITION BY子句的使用,如何创建运行总和,以及ROW_NUMBER和RANK函数在排名中的应用。内容涵盖按年分组的运行总和计算,按账户对订单总额进行排名,以及不同account_id下的聚合分析。

Window Function 1

PARTITION BY Clause

A PARTITION BY clause is used to partition rows of table into groups.

Syntax:

Window_function ( expression ) 
       Over ( partition by expr [order_clause] [frame_clause] ) 

order_clause and frame_clause are optional.
expr can be column names or built-in functions in MySQL.
But, standard SQL permits only column names in expr.

over() clause defines how to partition and order rows of table, which is to be processed by window function rank().

Running Total

select standard_qty,
		   date_trunc('month', occurred_at) as month,
		   sum(standard_qty) over (partition by date_trunc('month', occurred_at) order by occurred_at) as running_total
from orders;
  1. Using Derek’s previous video as an example, create another running total. This time, create a running total of standard_amt_usd (in the orders table) over order time with no date truncation. Your final table should have two columns: one with the amount being added for each new row, and a second with the running total.
SELECT standard_amt_usd,
       SUM(standard_amt_usd) OVER (ORDER BY occurred_at) 
<think> 我们正在讨论SQL中的窗口函数(Window Functions),用户询问了SQL Window的定义和作用。根据引用内容,特别是引用[1]和引用[4]中关于窗口函数的描述,我们可以总结如下: ### SQL窗口函数定义 窗口函数(Window Function)是SQL中一种高级分析函数,它允许在结果集的特定“窗口”(即行的子集)上执行计算,而不会将结果集折叠成单行(与聚合函数不同)。窗口函数的基本语法结构为: ```sql 函数名(参数) OVER ( [PARTITION BY 列名] [ORDER BY 列名 [ASC|DESC]] [window_frame] ) ``` ### 窗口函数的关键组成部分 1. **函数部分**:可以是以下类型之一: - 聚合函数:如`SUM()`, `AVG()`, `COUNT()`等 - 排名函数:如`ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`, `NTILE()` - 分析函数:如`LEAD()`, `LAG()`, `FIRST_VALUE()`, `LAST_VALUE()` 2. **OVER()子句**:定义窗口的范围,包含三个可选部分: - `PARTITION BY`:将结果集划分为逻辑分组(类似`GROUP BY`,但不会合并行) - `ORDER BY`:指定分区内行的排序顺序 - `window_frame`:定义窗口的精确范围(如滑动窗口) 3. **窗口帧(window_frame)**:指定计算时包含的具体行范围,常见选项: - `ROWS BETWEEN N PRECEDING AND M FOLLOWING`:基于物理行数的范围 - `RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`:基于值的逻辑范围 ### 窗口函数的作用 1. **跨行计算**:在保留原始明细行的同时,实现与聚合相关的计算 - 示例:计算每个员工的销售额占部门总额的百分比 ```sql SELECT employee_id, sales, department, sales/SUM(sales) OVER (PARTITION BY department) AS sales_percent FROM sales_data; ``` 2. **滑动窗口分析**:动态计算移动平均值、累计和等 - 示例:计算最近7天销售额的移动平均 ```sql SELECT date, sales, AVG(sales) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_avg FROM daily_sales; ``` 3. **排名与分桶**: - 示例:按销售额对部门内员工排名 ```sql SELECT employee_id, sales, department, RANK() OVER (PARTITION BY department ORDER BY sales DESC) AS dept_rank FROM sales_data; ``` 4. **跨行数据访问**: - 示例:获取上一条记录的值(用于计算环比) ```sql SELECT month, revenue, LAG(revenue, 1) OVER (ORDER BY month) AS prev_month_revenue FROM monthly_revenue; ``` ### 窗口函数的独特优势 ✅ **保留原始行**:不像`GROUP BY`会折叠行 ✅ **多层分析**:可在同一条查询中同时输出明细和聚合结果 ✅ **动态范围**:通过窗口帧实现灵活的计算范围控制 > **典型应用场景**: > - 财务报表中的累计计算(YTD/QTD) > - 用户行为分析(会话内事件序列) > - 实时流处理(如Flink SQL中的Window TopN[^3]) §§相关问题§§ 1. 窗口函数与普通聚合函数的核心区别是什么? 2. 如何在窗口函数中正确使用`ROWS`和`RANGE`子句? 3. 窗口函数在实时流处理(如Flink)中有哪些特殊应用? 4. 如何优化包含窗口函数的复杂SQL查询性能? 5. 窗口函数在Oracle/MySQL/PG等不同数据库中的实现差异? </think> ### SQL Window 的定义与作用详解 #### 💡 **定义** SQL Window(窗口函数)是一种高级分析函数,它在结果集的特定**窗口(行子集)** 上执行计算,同时保留原始明细行。其核心语法结构为: ```sql 函数名() OVER ( [PARTITION BY 分区字段] [ORDER BY 排序字段] [窗口帧子句] ) ``` #### 🔍 **核心组件解析** 1. **分区(PARTITION BY)** - 将数据集划分为逻辑分组(类似 GROUP BY) - 示例:按部门分区计算 ```sql SELECT name, salary, AVG(salary) OVER (PARTITION BY dept) AS dept_avg FROM employees; ``` 2. **排序(ORDER BY)** - 定义分区内的行顺序,影响累计计算 - 示例:按日期排序计算累计销售额 ```sql SELECT order_date, amount, SUM(amount) OVER (ORDER BY order_date) AS running_total FROM sales; ``` 3. **窗口帧(Window Frame)** [^1][^4] - 精确控制计算范围,支持滑动窗口 - 常用语法: ```sql ROWS BETWEEN N PRECEDING AND M FOLLOWING ``` - 示例:计算近3天移动平均 ```sql SELECT date, revenue, AVG(revenue) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS mov_avg FROM daily_sales; ``` #### **核心作用** 1. **跨行计算** - 保留明细行同时实现聚合(如排名、累计值) - 对比 GROUP BY:不折叠结果集 2. **动态分析** - 实时计算:移动平均、环比增长率等 - 场景示例:股票价格波动分析 3. **排名与分桶** - 实现高级排序逻辑: ```sql -- 部门内薪资排名 SELECT name, salary, RANK() OVER (PARTITION BY dept ORDER BY salary DESC) FROM employees; ``` 4. **时序处理** - 处理时间序列数据(如 Flink SQL 中的 Window TopN[^3]) - 示例:每5分钟统计Top 3热门商品 #### 🌰 **典型应用场景** ```sql -- 案例:计算每个员工薪资与部门平均薪资的差值 SELECT emp_id, salary, dept, AVG(salary) OVER (PARTITION BY dept) AS dept_avg, salary - AVG(salary) OVER (PARTITION BY dept) AS diff_from_avg FROM employees; ``` | emp_id | salary | dept | dept_avg | diff_from_avg | |--------|--------|------|----------|--------------| | 101 | 8000 | IT | 7500 | 500 | | 102 | 7000 | IT | 7500 | -500 | #### ⚠️ **注意事项** 1. 执行顺序:窗口函数在 `WHERE` 和 `GROUP BY` 之后执行 2. 性能优化:避免全表扫描,配合索引使用 3. 数据库差异:Oracle/MySQL/PG 实现细节不同(如 MySQL 8.0+ 才支持) > **💡 本质区别**: > 普通聚合函数:`SELECT SUM(salary) FROM employees` → **单结果行** > 窗口函数:`SELECT SUM(salary) OVER() FROM employees` → **保留所有明细行**
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值