在学习窗口函数之前,我们新建一个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 <排序用列清单>)

窗口函数大体分为以下两种:

  1. 能够作为窗口函数的聚合函数(SUM、AVG、COUNT、MAX、MIN)
  2. 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学习笔记——窗口函数的更多相关文章

  1. PostgreSQL学习笔记——摘要

    因为PostgreSQL和MySQL.DB2等数据库均遵循SQL语法,所以这篇随笔仅记录一些PostgreSQL中和别的数据库有差别或之前学习中遗漏的地方,以及一些我觉得比较重点的地方. 通过psql ...

  2. SQL2005 学习笔记 窗口函数(OVER)【转】

    1.简介: SQL Server 2005中的窗口函数帮助你迅速查看不同级别的聚合,通过它可以非常方便地累计总数.移动平均值.以及执行其它计算. 窗口函数功能非常强大,使用起来也十分容易.可以使用这个 ...

  3. PostgreSQL学习笔记(二)-安装pgAdmin

    继上篇安装PostgreSQL后,我们需要安装一个PostgreSQL的图形化管理工具. pgadmin管理工具 创建Python的虚拟环境 cd /root/venv python -m venv ...

  4. PostgreSQL学习笔记(一)-安装PostgreSQL

    PostgreSQL官网:https://www.postgresql.org/docs/11/index.html1.如何安装2.如何修改配置文件3.如何设置自动启动4.如何修改数据用户密码 本文环 ...

  5. jsp+postgresql学习笔记(1)用户登录与注册

    前期准备: tomcat的安装与配置(略) jdk的安装与配置(略) eclipse软件安装与配置(略) webstrom软件或IDEA的安装与配置(大概用了IDEA就不需要eclipse了,但是怎么 ...

  6. Postgresql学习笔记

    一:数据类型 主要有三大类以及其他一些杂项类型: 数值型.字符型.日期型. 数值型: 名称 描述 存储大小 范围 smallint 存储整数,小范围 2字节 -32768 至 +32767 integ ...

  7. PostgreSQL学习笔记(二)—— 概览

    数据库 创建数据库: createdb dbname 指定用户名创建数据库: createdb -U username dbname 删除数据库: dropdb dbname 访问数据库: psql ...

  8. PostgreSQL学习笔记(一)—— macOS下安装

    安装命令:brew install postgresql 我的终端是zsh,所以添加环境变量到~/.zshrc vim ~/.zshrc export PATH=$PATH:/usr/local/Ce ...

  9. PostgreSQL学习笔记(九) 用户、角色、权限管理

    PostgreSQL是一个多用户数据库,可以为不同用户指定允许的权限. 角色PostgreSQL使用角色的概念管理数据库访问权限. 根据角色自身的设置不同,一个角色可以看做是一个数据库用户,或者一组数 ...

随机推荐

  1. vue子父组件传值

    https://blog.csdn.net/weixin_38888773/article/details/81902789 https://blog.csdn.net/jsxiaoshu/artic ...

  2. java调出cmd窗口长ping某个ip

    package lct.conference.test; import java.io.IOException; public class Test { public static void main ...

  3. myeclipse关掉references

    去掉下面两个勾选:

  4. pyexcel_xlsx

    from pyexcel_xlsx import get_data,save_data excel_data = get_data('xxxx.xlsx文件存储位置') #得到的excel_data是 ...

  5. Python中字符串与字节之间相互转换

    Python中字符串与字节之间相互转换 ​ a = b"Hello, world!" # bytes object b = "Hello, world!" # ...

  6. P2313 [HNOI2005]汤姆的游戏

    题目描述 汤姆是个好动的孩子,今天他突然对圆规和直尺来了兴趣.于是他开始在一张很大很大的白纸上画很多很多的矩形和圆.画着画着,一不小心将他的爆米花弄撒了,于是白纸上就多了好多好多的爆米花.汤姆发现爆米 ...

  7. python #!/usr/bin/python 的作用

    在说之前,这里推荐写: #!/usr/bin/env python 进入正题,在 Python 里面第一行代码: #!/usr/bin/python 其他有的可能是 python2 或者 python ...

  8. jsp页面中的EL表达式不被解析org.apache.jasper.JasperException: Unable to convert string [${item.createtime}]

    https://m.imooc.com/qadetail/277572 web.xml的版本是不是2.3, 如果是2.3,在jsp页面开头添加<%@ page isELIgnored=" ...

  9. 【SPOJ】Longest Common Substring

    [SPOJ]Longest Common Substring 求两个字符串的最长公共子串 对一个串建好后缀自动机然后暴力跑一下 废话 讲一下怎么跑吧 从第一个字符开始遍历,遍历不到了再沿着\(pare ...

  10. zabbix (6) 为主机添加监控项,触发器,动作

    先了解一下zabbix的相关概念 监控项(iterms):一个具体的指标,比如某个人的体重. 键(key):通过定义(自定义或者zabbix自带)的key获取相应指标的具体值,比如这个人的体重50斤 ...