在学习窗口函数之前,我们新建一个Product表并往其中插入一些数据:

  1. drop table if exists Product;
  2. create table Product
  3. (
  4. product_id char(4) not null,
  5. product_name varchar(100) not null,
  6. product_type varchar(32) not null,
  7. sale_price integer ,
  8. purchase_price integer ,
  9. regist_date date ,
  10. primary key (product_id)
  11. );
  12. begin transaction;
  13. insert into Product values ('0001', 'T恤衫', '衣服', 100, 50, '2018-10-10');
  14. insert into Product values ('0002', '打孔器', '办公用品', 50, 30, '2018-10-25');
  15. insert into Product values ('0003', '运动T恤', '衣服', 400, 280, '2018-10-01');
  16. insert into Product values ('0004', '菜刀', '厨房用具', 300, 280, '2018-11-11');
  17. insert into Product values ('0005', '高压锅', '厨房用具', 680, 500, '2018-10-22');
  18. insert into Product values ('0006', '叉子', '厨房用具', 50, NULL, '2018-10-08');
  19. insert into Product values ('0007', '擦菜纸', '厨房用具', 88, 66, '2018-11-12');
  20. insert into Product values ('0008', '圆珠笔', '办公用品', 100, NULL, '2018-10-25');
  21. commit;

什么是窗口函数

窗口函数 也称为 OLAP函数

OLAP是OnLine Analytical Processing的简称,意思是对数据库数据进行实时分析处理。例如:市场分析、创建财务报表、创建计划等日常性商务工作。

窗口函数就是为了实现OLAP而添加的标准SQL功能。

窗口函数的语法

  1. <窗口函数> 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)从低到高的顺序排序:

  1. select product_name, product_type, sale_price,
  2. rank() over (partition by product_type
  3. order by sale_price) as ranking
  4. 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子句,如下:

  1. select product_name, product_type, sale_price,
  2. rank() over (
  3. order by sale_price) as ranking
  4. 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函数作为聚合函数使用:

  1. select product_name, product_type, sale_price,
  2. sum(sale_price) over (order by product_id) as current_sum
  3. 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函数作为窗口函数使用:

  1. select product_name, product_type, sale_price,
  2. avg(sale_price) over (order by product_id) as current_avg
  3. 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:

  1. select product_name, product_type, sale_price,
  2. avg(sale_price) over (order by product_id
  3. rows 2 preceding) as moving_avg
  4. 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 ,就可以指定“包含之后的几行”。

示例:将当前记录的前后行作为汇总对象:

  1. select product_name, product_type, sale_price,
  2. avg(sale_price) over (order by product_id
  3. rows between 1 preceding and 1 following) as moving_avg
  4. 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子句,例:

  1. select product_name, product_type, sale_price,
  2. rank() over (order by sale_price) as ranking
  3. from Product
  4. 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. CentOS 6.5下快速搭建ftp服务器

    来源:Linux社区 作者:Linux CentOS 6.5下快速搭建ftp服务器 1.用root 进入系统 2.使用命令 rpm -qa|grep vsftpd 查看系统是否安装了ftp,若安装了v ...

  2. Java7--try - with - resources

    从 Java 7 build 105 版本开始,Java 7 的编译器和运行环境支持新的 try-with-resources 语句,称为 ARM 块(Automatic Resource Manag ...

  3. vue2 自定义过滤器

  4. js 实现多文件批量下载

    关于兼容性问题: <a href="xxx.docx" target='_blank'></a> 下载文件时,这种写法是没有兼容性问题:但是下载图片时,IE ...

  5. 历年NOIP题

    做了几天远古老题,发现不可做,于是咕掉..转而从2005开始.. 1997: P1549 棋盘问题(2):搜索,优化搜索顺序,对于第一行第一列先搜小的(但是其实这样是错的,仅仅能过原题) 加强版咕. ...

  6. HTML 007 链接

    HTML 链接 HTML 使用超级链接与网络上的另一个文档相连.几乎可以在所有的网页中找到链接.点击链接可以从一张页面跳转到另一张页面. 尝试一下 - 实例 HTML 链接如何在HTML文档中创建链接 ...

  7. Linux分区格式化

    格式化(format)是指对磁盘或磁盘中的分区(partition)进行初始化的一种操作,这种操作通常会导致现有的磁盘或分区中所有的文件被清除.格式化通常分为低级格式化和高级格式化.如果没有特别指明, ...

  8. 代码 | 用ALNS框架求解一个TSP问题 - 代码详解

    写在前面 前面好多篇文章,我们总算是把整个ALNS的代码框架给大家说明白了.不知道大家对整个框架了解了没有.不过打铁要趁热,心急了要吃热豆腐.今天就来实战一下,教大家怎么用ALNS的代码框架,求解一个 ...

  9. Linux使用Aria2命令下载BT种子/磁力/直链文件 转载

    Linux使用Aria2命令下载BT种子/磁力/直链文件 博主: Rat's 发布时间:2017 年 10 月 10 日 26725 次浏览 8 条评论 1073 字数 分类:主机教程 首页 正文 分 ...

  10. Python3 内置http.client,urllib.request及三方库requests发送请求对比

    如有任何学习问题,可以添加作者微信:lockingfree 更多学习资料请加QQ群: 822601020获取 HTTP,GET请求,无参 GET http://httpbin.org/get Pyth ...