PostgreSQL学习笔记——窗口函数
在学习窗口函数之前,我们新建一个Product表并往其中插入一些数据:
drop table if exists Product;
create table Product
(
product_id char(4) not null,
product_name varchar(100) not null,
product_type varchar(32) not null,
sale_price integer ,
purchase_price integer ,
regist_date date ,
primary key (product_id)
);
begin transaction;
insert into Product values ('0001', 'T恤衫', '衣服', 100, 50, '2018-10-10');
insert into Product values ('0002', '打孔器', '办公用品', 50, 30, '2018-10-25');
insert into Product values ('0003', '运动T恤', '衣服', 400, 280, '2018-10-01');
insert into Product values ('0004', '菜刀', '厨房用具', 300, 280, '2018-11-11');
insert into Product values ('0005', '高压锅', '厨房用具', 680, 500, '2018-10-22');
insert into Product values ('0006', '叉子', '厨房用具', 50, NULL, '2018-10-08');
insert into Product values ('0007', '擦菜纸', '厨房用具', 88, 66, '2018-11-12');
insert into Product values ('0008', '圆珠笔', '办公用品', 100, NULL, '2018-10-25');
commit;
什么是窗口函数
窗口函数 也称为 OLAP函数 。
OLAP是OnLine Analytical Processing的简称,意思是对数据库数据进行实时分析处理。例如:市场分析、创建财务报表、创建计划等日常性商务工作。
窗口函数就是为了实现OLAP而添加的标准SQL功能。
窗口函数的语法
<窗口函数> OVER ([PARTITION BY <列清单>] ORDER BY <排序用列清单>)
窗口函数大体分为以下两种:
- 能够作为窗口函数的聚合函数(SUM、AVG、COUNT、MAX、MIN)
- RANK、DENSE_RANK、ROW_NUMBER等 专用窗口函数
语法的基本使用——使用RANK函数
RANK是用来计算记录排序的函数。
对于Product表中的8件商品,使用如下SQL可以根据不同的商品种类(product_type),按照销售单价(sale_price)从低到高的顺序排序:
select product_name, product_type, sale_price,
rank() over (partition by product_type
order by sale_price) as ranking
from Product;
结果如下所示:
| product_name | product_type | sale_price | ranking |
|---|---|---|---|
| 打孔器 | 办公用品 | 50 | 1 |
| 圆珠笔 | 办公用品 | 100 | 2 |
| 叉子 | 厨房用具 | 50 | 1 |
| 擦菜纸 | 厨房用具 | 88 | 2 |
| 菜刀 | 厨房用具 | 300 | 3 |
| 高压锅 | 厨房用具 | 680 | 4 |
| T恤衫 | 衣服 | 100 | 1 |
| 运动T恤 | 衣服 | 400 | 2 |
以厨房用具为例,最便宜的“叉子”排在第1位,最贵的“高压锅”排在第4位,确实按照我们的要求进行了排序。
PARTITION BY能够设定排序的对象范围。ORDER BY能够指定按照哪一列、何种顺序进行排序。
无需指定PARTITION BY
我们删除上面SQL的PARTITION BY子句,如下:
select product_name, product_type, sale_price,
rank() over (
order by sale_price) as ranking
from Product;
结果如下:
| product_name | product_type | sale_price | ranking |
|---|---|---|---|
| 叉子 | 厨房用具 | 50 | 1 |
| 打孔器 | 办公用品 | 50 | 1 |
| 擦菜纸 | 厨房用具 | 88 | 3 |
| T恤衫 | 衣服 | 100 | 4 |
| 圆珠笔 | 办公用品 | 100 | 4 |
| 菜刀 | 厨房用具 | 300 | 6 |
| 运动T恤 | 衣服 | 400 | 7 |
| 高压锅 | 厨房用具 | 680 | 8 |
之前我们得到的是按照商品种类分组后的排序,而这次变成了全部商品的排序。
专用窗口函数的种类
接下来我们来总结以下具有代表性的专用窗口函数:
RANK函数
计算排序时,如果存在相同位次的记录,则会跳过之后的位次。
例)有3条记录排在第一位时,1位、1位、1位、4位……
DENSE_RANK函数
计算排序时,即使存在相同位次的记录,也不会跳过之后的位次。
例)有3条记录排在第一位时,1位、1位、1位、2位……
ROW_NUMBER函数
赋予唯一的连续位次。
例)有3条记录排在第一位时,1位、2位、3位、4位……
窗口函数的适用范围
窗口函数只能放在SELECT子句之中。
也就是说,这类函数不能再WHERE子句或者GROUP BY子句中使用。
作为窗口函数使用的聚合函数
将SUM函数作为聚合函数使用:
select product_name, product_type, sale_price,
sum(sale_price) over (order by product_id) as current_sum
from Product;
结果:
| product_name | product_type | sale_price | current_sum | 解释 |
|---|---|---|---|---|
| T恤衫 | 衣服 | 100 | 100 | <--100 |
| 打孔器 | 办公用品 | 50 | 150 | <--100+50 |
| 运动T恤 | 衣服 | 400 | 550 | <--100+50+400 |
| 菜刀 | 厨房用具 | 300 | 850 | |
| 高压锅 | 厨房用具 | 680 | 1530 | |
| 叉子 | 厨房用具 | 50 | 1580 | |
| 擦菜纸 | 厨房用具 | 88 | 1668 | |
| 圆珠笔 | 办公用品 | 100 | 1768 |
窗口函数一般都会使用这种称为 累计 的统计方法。
将AVG函数作为窗口函数使用:
select product_name, product_type, sale_price,
avg(sale_price) over (order by product_id) as current_avg
from Product;
结果:
| product_name | product_type | sale_price | current_avg | 解释 |
|---|---|---|---|---|
| T恤衫 | 衣服 | 100 | 100.0000000000000000 | <--(100)/1 |
| 打孔器 | 办公用品 | 50 | 75.0000000000000000 | <--(100+50)/2 |
| 运动T恤 | 衣服 | 400 | 183.3333333333333333 | <--(100+50+400)/3 |
| 菜刀 | 厨房用具 | 300 | 212.5000000000000000 | |
| 高压锅 | 厨房用具 | 680 | 306.0000000000000000 | |
| 叉子 | 厨房用具 | 50 | 263.3333333333333333 | |
| 擦菜纸 | 厨房用具 | 88 | 238.2857142857142857 | |
| 圆珠笔 | 办公用品 | 100 | 221.0000000000000000 |
从以上两个结果中我们可以看到,current_sum和current_avg的计算方法都是包含“排在自己之上”的记录。像这样的“自身记录( 当前记录 )”作为基准进行统计,就是将聚合函数当作窗口函数使用时的最大特征。
计算移动平均
执行如下SQL:
select product_name, product_type, sale_price,
avg(sale_price) over (order by product_id
rows 2 preceding) as moving_avg
from Product;
结果:
| product_name | product_type | sale_price | moving_avg | 解释 |
|---|---|---|---|---|
| T恤衫 | 衣服 | 100 | 100.0000000000000000 | <-- (100)/1 |
| 打孔器 | 办公用品 | 50 | 75.0000000000000000 | <-- (100+50)/2 |
| 运动T恤 | 衣服 | 400 | 183.3333333333333333 | <-- (100+50+400)/3 |
| 菜刀 | 厨房用具 | 300 | 250.0000000000000000 | <-- (50+400+300)/3 |
| 高压锅 | 厨房用具 | 680 | 460.0000000000000000 | <-- (400+300+600)/3 |
| 叉子 | 厨房用具 | 50 | 343.3333333333333333 | |
| 擦菜纸 | 厨房用具 | 88 | 272.6666666666666667 | |
| 圆珠笔 | 办公用品 | 100 | 79.3333333333333333 |
可以发现第4行数据和之前的结果不一样了,这是因为我们指定了“框架”,将汇总对象限定为了“最靠近的3行”。
这里我们使用 ROW (“行”)和 PRECEDING (“之前”)两个关键字,限定的查询的结果只包含本身这行和它之前的两行(如果有的话)。
使用关键字 FOLLOWING (“之后”)替换 PRECEDING ,就可以指定“包含之后的几行”。
示例:将当前记录的前后行作为汇总对象:
select product_name, product_type, sale_price,
avg(sale_price) over (order by product_id
rows between 1 preceding and 1 following) as moving_avg
from Product;
结果:
| product_name | product_type | sale_price | moving_avg |
|---|---|---|---|
| T恤衫 | 衣服 | 100 | 75.0000000000000000 |
| 打孔器 | 办公用品 | 50 | 183.3333333333333333 |
| 运动T恤 | 衣服 | 400 | 250.0000000000000000 |
| 菜刀 | 厨房用具 | 300 | 460.0000000000000000 |
| 高压锅 | 厨房用具 | 680 | 343.3333333333333333 |
| 叉子 | 厨房用具 | 50 | 272.6666666666666667 |
| 擦菜纸 | 厨房用具 | 88 | 79.3333333333333333 |
| 圆珠笔 | 办公用品 | 100 | 94.0000000000000000 |
两个ORDER BY
OVER子句中的ORDER BY只是用来决定窗口函数按照什么样的顺序进行计算的,对结果的顺序并没有影响。所以,要对结果进行排序,还需要添加另一个ORDER BY子句,例:
select product_name, product_type, sale_price,
rank() over (order by sale_price) as ranking
from Product
order by ranking;
结果:
| product_name | product_type | sale_price | ranking |
|---|---|---|---|
| 叉子 | 厨房用具 | 50 | 1 |
| 打孔器 | 办公用品 | 50 | 1 |
| 擦菜纸 | 厨房用具 | 88 | 3 |
| T恤衫 | 衣服 | 100 | 4 |
| 圆珠笔 | 办公用品 | 100 | 4 |
| 菜刀 | 厨房用具 | 300 | 6 |
| 运动T恤 | 衣服 | 400 | 7 |
| 高压锅 | 厨房用具 | 680 | 8 |
PostgreSQL学习笔记——窗口函数的更多相关文章
- PostgreSQL学习笔记——摘要
因为PostgreSQL和MySQL.DB2等数据库均遵循SQL语法,所以这篇随笔仅记录一些PostgreSQL中和别的数据库有差别或之前学习中遗漏的地方,以及一些我觉得比较重点的地方. 通过psql ...
- SQL2005 学习笔记 窗口函数(OVER)【转】
1.简介: SQL Server 2005中的窗口函数帮助你迅速查看不同级别的聚合,通过它可以非常方便地累计总数.移动平均值.以及执行其它计算. 窗口函数功能非常强大,使用起来也十分容易.可以使用这个 ...
- PostgreSQL学习笔记(二)-安装pgAdmin
继上篇安装PostgreSQL后,我们需要安装一个PostgreSQL的图形化管理工具. pgadmin管理工具 创建Python的虚拟环境 cd /root/venv python -m venv ...
- PostgreSQL学习笔记(一)-安装PostgreSQL
PostgreSQL官网:https://www.postgresql.org/docs/11/index.html1.如何安装2.如何修改配置文件3.如何设置自动启动4.如何修改数据用户密码 本文环 ...
- jsp+postgresql学习笔记(1)用户登录与注册
前期准备: tomcat的安装与配置(略) jdk的安装与配置(略) eclipse软件安装与配置(略) webstrom软件或IDEA的安装与配置(大概用了IDEA就不需要eclipse了,但是怎么 ...
- Postgresql学习笔记
一:数据类型 主要有三大类以及其他一些杂项类型: 数值型.字符型.日期型. 数值型: 名称 描述 存储大小 范围 smallint 存储整数,小范围 2字节 -32768 至 +32767 integ ...
- PostgreSQL学习笔记(二)—— 概览
数据库 创建数据库: createdb dbname 指定用户名创建数据库: createdb -U username dbname 删除数据库: dropdb dbname 访问数据库: psql ...
- PostgreSQL学习笔记(一)—— macOS下安装
安装命令:brew install postgresql 我的终端是zsh,所以添加环境变量到~/.zshrc vim ~/.zshrc export PATH=$PATH:/usr/local/Ce ...
- PostgreSQL学习笔记(九) 用户、角色、权限管理
PostgreSQL是一个多用户数据库,可以为不同用户指定允许的权限. 角色PostgreSQL使用角色的概念管理数据库访问权限. 根据角色自身的设置不同,一个角色可以看做是一个数据库用户,或者一组数 ...
随机推荐
- matlab(7) Regularized logistic regression : mapFeature(将feature增多) and costFunctionReg
Regularized logistic regression : mapFeature(将feature增多) and costFunctionReg ex2_reg.m文件中的部分内容 %% == ...
- XSLT格式
XSL 指扩展样式表语言(EXtensible Stylesheet Language). XSL - 不仅仅是样式表语言,包括三部分: XSLT :一种用于转换 XML 文档的语言. XPath : ...
- Oracle LOB 大对象处理
LOB类型列主要是用来存储大量数据的数据库字段,最大可以存储4G字节的非结构化数据. 一.LOB数据类型分类 1.按存储数据的类型分: ①字符类型: CLOB:存储大量 单字节 字符数据. N ...
- 树莓派远程桌面--使用windows自带的远程桌面软件mstsc.exe
步骤: 1.使用SSH登录树莓派 2.安装xrdp服务: sudo apt-get install xrdp 3.在Windows下打开命令框运行:mstsc 4.登录树莓派桌面 5.登录成功
- VSCodeUserSetup安装教程
VSCodeUserSetup: isual Studio Code是一个轻量级但功能强大的源代码编辑器,可在桌面上运行,适用于Windows,macOS和Linux.它内置了对JavaScript, ...
- 洛谷 P3627 [APIO2009]抢掠计划 题解
Analysis 建图+强连通分量+SPFA求最长路 但要保证最后到达的点中包含酒馆 虽然思路并不难想,但要求的代码能力很高. #include<iostream> #include< ...
- Greenplum 常用数据字典
一.数据库集群信息 1.gp_segment_configration 2.pg_filespace_entry 这两个表是在pg_global表空间下面的,是全局表. 用来查看集群segment信息 ...
- BZOJ 4300: 绝世好题 二进制
对于每一个数字拆位,然后维护一个大小为 30 左右的桶即可. code: #include <bits/stdc++.h> #define N 100006 #define setIO(s ...
- ROS计算图级
上一节说到一个 package 可以包含多个可执行文件(节点),可执行文件需要被运行,就要了解ROS的通信架构,也就是计算图级,例: 小萝卜机器人拥有驱动系统,感知系统,控制系统等,要让它从指定位置到 ...
- Python如何import其它.py文件及其函数
如上图所示,我想在test_1.py文件中import我在lstm_1.py中定义的LstmParam和 LstmNetwork.我直接采用的是最简单的引用方法:from lstm_1 impor ...