postgresql-窗口函数

本文详细介绍了PostgreSQL中的窗口函数,包括其定义、使用OVER子句中的分区、排序和窗口选项,以及举例说明了聚合函数、排名和累计销量的计算。

窗口函数简介

包括 AVG、COUNT、MAX、MIN、SUM 以及
STRING_AGG。聚合函数的作用是针对一组数据行进行运算,并且返回一条汇总结果
分析的窗口函数(Window Function)。
不过,窗口函数不是将一组数据汇总为单个结果,而是针对每一行数据,基于和它相关的一组数
据计算出一个结果。下图演示了聚合函数和窗口函数的区别
在这里插入图片描述
区别在于后者包含了 OVER 关键字;空括号表示将所有数据作为整体进行分析,所以得到的数值和聚合函数一样

窗口函数的定义

window_function ( expression, ... ) OVER (
 PARTITION BY ...
 ORDER BY ...
 frame_clause
)

window_function 是窗口函数的名称;expression 是函数参数,有些函数不需要参数;
over 子句包含三个选项:分区(partition by)、排序(order by)以及窗口大小
frame_clause

分区

-- 计算员工的部门平均薪水
-- partition by分组统计,和group by 类似
select 
e.employee_id ,
e.first_name ,
e.last_name ,
e.salary ,
e.department_id ,
round(avg(e.salary) over(partition by e.department_id),2) as avg_sal
from employees e;

在这里插入图片描述
partition by 选项用于定义分区,作用类似于 group by 的分组。如果指定了分区选项,
窗口函数将会分别针对每个分区单独进行分析;如果省略分区选项,所有的数据作为一个整体进
行分析

排序选项

order by 选项用于指定分区内的排序方式,通常用于数据的排名分析

-- 员工在部门内薪水排名
select 
e.employee_id ,
e.first_name ,
e.last_name,
e.salary ,
e.department_id ,
rank() over(partition by e.department_id order by e.salary desc)
from employees e;

在这里插入图片描述

窗口选项

frame_clause 选项用于在当前分区内指定一个计算窗口。指定了窗口之后,分析函数不再基
于分区进行计算,而是基于窗口内的数据进行计算

-- public.sales_monthly definition

-- Drop table

-- DROP TABLE public.sales_monthly;

CREATE TABLE public.sales_monthly (
	product varchar(20) NULL,
	ym varchar(10) NULL,
	amount numeric(10, 2) NULL
);
INSERT INTO public.sales_monthly (product,ym,amount) VALUES
	 ('苹果','201801',10159.00),
	 ('苹果','201802',10211.00),
	 ('苹果','201803',10247.00),
	 ('苹果','201804',10376.00),
	 ('苹果','201805',10400.00),
	 ('苹果','201806',10565.00),
	 ('苹果','201807',10613.00),
	 ('苹果','201808',10696.00),
	 ('苹果','201809',10751.00),
	 ('苹果','201810',10842.00);
INSERT INTO public.sales_monthly (product,ym,amount) VALUES
	 ('苹果','201811',10900.00),
	 ('苹果','201812',10972.00),
	 ('苹果','201901',11155.00),
	 ('苹果','201902',11202.00),
	 ('苹果','201903',11260.00),
	 ('苹果','201904',11341.00),
	 ('苹果','201905',11459.00),
	 ('苹果','201906',11560.00),
	 ('香蕉','201801',10138.00),
	 ('香蕉','201802',10194.00);
INSERT INTO public.sales_monthly (product,ym,amount) VALUES
	 ('香蕉','201803',10328.00),
	 ('香蕉','201804',10322.00),
	 ('香蕉','201805',10481.00),
	 ('香蕉','201806',10502.00),
	 ('香蕉','201807',10589.00),
	 ('香蕉','201808',10681.00),
	 ('香蕉','201809',10798.00),
	 ('香蕉','201810',10829.00),
	 ('香蕉','201811',10913.00),
	 ('香蕉','201812',11056.00);
INSERT INTO public.sales_monthly (product,ym,amount) VALUES
	 ('香蕉','201901',11161.00),
	 ('香蕉','201902',11173.00),
	 ('香蕉','201903',11288.00),
	 ('香蕉','201904',11408.00),
	 ('香蕉','201905',11469.00),
	 ('香蕉','201906',11528.00),
	 ('桔子','201801',10154.00),
	 ('桔子','201802',10183.00),
	 ('桔子','201803',10245.00),
	 ('桔子','201804',10325.00);
INSERT INTO public.sales_monthly (product,ym,amount) VALUES
	 ('桔子','201805',10465.00),
	 ('桔子','201806',10505.00),
	 ('桔子','201807',10578.00),
	 ('桔子','201808',10680.00),
	 ('桔子','201809',10788.00),
	 ('桔子','201810',10838.00),
	 ('桔子','201811',10942.00),
	 ('桔子','201812',10988.00),
	 ('桔子','201901',11099.00),
	 ('桔子','201902',11181.00);
INSERT INTO public.sales_monthly (product,ym,amount) VALUES
	 ('桔子','201903',11302.00),
	 ('桔子','201904',11327.00),
	 ('桔子','201905',11423.00),
	 ('桔子','201906',11524.00);

/*
 * 计算每个产品当当前月份的累计销量
*/
select
	m.product ,
	m.ym ,
	m.amount,
	sum(m.amount) over(partition by m.product 
	order by m.ym rows between unbounded  preceding and current row)
from
	sales_monthly m
	order by m.product,m.ym;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
常见的窗口函数可以分为以下几类:聚合窗口函数、排名窗口函数以及取值窗口函数。
更多的复杂选项可以参考官方文档

### PostgreSQL 窗口函数使用指南 PostgreSQL 中的窗口函数(Window Function)是一种强大的分析工具,允许在一组相关的行上执行计算,同时保持每一行的独立性。这与聚合函数不同,后者通常会将多行合并为单个结果值。窗口函数则允许在不丢失行细节的情况下进行分组计算。 #### 窗口函数的基本语法 窗口函数的基本语法如下: ```sql function_name (expression) OVER ( [PARTITION BY partition_expression] [ORDER BY sort_expression [ASC | DESC] [NULLS {FIRST | LAST}]] [frame_clause] ) ``` 其中: - `function_name` 可以是 `ROW_NUMBER`、`RANK`、`DENSE_RANK`、`LEAD`、`LAG`、`SUM`、`AVG` 等。 - `PARTITION BY` 将数据划分为多个分区,每个分区独立计算。 - `ORDER BY` 定义窗口内行的排序方式。 - `frame_clause` 定义窗口框架,例如 `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`。 #### 常见窗口函数示例 ##### 1. `ROW_NUMBER`:为每一行分配一个唯一的行号 ```sql SELECT name, department, salary, ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank FROM employees; ``` 该查询为每个部门的员工按薪资从高到低分配一个行号[^1]。 ##### 2. `RANK`:排名函数,允许并列,但后续排名会跳过 ```sql SELECT name, department, salary, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank FROM employees; ``` 如果有多个员工薪资相同,它们将获得相同的排名,后续排名会跳过相应的数值[^2]。 ##### 3. `DENSE_RANK`:与 `RANK` 类似,但后续排名不跳过 ```sql SELECT name, department, salary, DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rank FROM employees; ``` 此函数在处理并列排名时不会跳过后续的排名数值[^3]。 ##### 4. `LEAD` 和 `LAG`:访问当前行之后或之前的行 ```sql SELECT name, salary, LEAD(salary, 1) OVER (ORDER BY salary DESC) AS next_salary, LAG(salary, 1) OVER (ORDER BY salary DESC) AS prev_salary FROM employees; ``` `LEAD` 获取当前行之后的行数据,`LAG` 获取当前行之前的行数据。 ##### 5. `SUM` 和 `AVG`:计算窗口内的累计总和或平均值 ```sql SELECT name, salary, SUM(salary) OVER (ORDER BY salary ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total FROM employees; ``` 该查询计算薪资的累计总和,使用 `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` 定义从第一行到当前行的窗口范围。 #### 窗口函数的使用场景 - **排名分析**:如部门内薪资排名、销售排名等。 - **趋势分析**:通过 `LEAD` 和 `LAG` 获取相邻数据进行比较。 - **累计统计**:计算累计总和、平均值等。 - **数据透视**:将多行数据转换为单行输出,保留原始行信息。 #### 窗口函数与 GROUP BY 的区别 窗口函数与 `GROUP BY` 的主要区别在于:`GROUP BY` 会将多行合并为一行,而窗口函数保留每一行的数据,并在不改变行数的情况下进行聚合计算。例如,使用 `GROUP BY` 计算部门平均薪资会丢失员工个体信息,而使用窗口函数可以在每行中显示员工信息及其部门平均薪资: ```sql SELECT name, department, salary, AVG(salary) OVER (PARTITION BY department) AS avg_salary FROM employees; ``` 该查询中,每个员工的薪资与其部门的平均薪资一同显示,未丢失任何员工记录。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值