在学习窗口函数之前,我们新建一个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. 28-SQLServer带见证服务器的镜像搭建

    一.注意点 1.数据库的模式要是完整模式. 2.要对数据库完整备份和事务日志备份,分别还原到镜像库上,使用NORECOVERY模式. 3.镜像数据库是不允许删除和操作,即便查看属性也不行. 4.先删除 ...

  2. ask confirm shell

    #/bin/bash BASEDIR=$(cd $() && pwd) cd $BASEDIR>/dev/null usage="Usage: $0 -o/--org ...

  3. Greenplum 查看表的分区键与分区类型

    方法一 查看表的分区键 select d.nspname||'.'||a.relname as table_name,string_agg(b.attname,',') as column_namef ...

  4. Mina入门级客户端程序实现telnet程序

    Mina入门级客户端程序实现telnet程序,其实mina的客户端和服务端很相似 1.编写客户端MinaClient.java和客户端处理类MyClientHandler.java2.MinaClie ...

  5. Apache的安装和配置

    一.官网下载Apache 官网地址:https://httpd.apache.org/ 点击Download--->点击Files for Microsoft Windows--->点击A ...

  6. [luogu] zpl的数学题1

    https://www.luogu.org/problemnew/show/U16887 $f[1] + f[2] + f[3] + .... + f[n] = f[n + 2] - 1$ 矩阵快速幂 ...

  7. Linux find,grep 命令

    使用实验楼Linux环境开发,部分内容有所参考,link:https://www.shiyanlou.com/ 概述: find: 在目录中搜索文件,它的使用权限是所有用户 命令格式: find [路 ...

  8. Mac cpu过高问题分析及解决

    1.mds.mds_stores.mdworker 关闭: sudo mdutil -a -i off 打开: sudo mdutil -a -i on

  9. hadoop namenode启动失败

    hadoop version=3.1.2 生产环境中,一台namenode节点突然挂掉了,,重新启动失败,日志如下: Info=-64%3A1391355681%3A1545175191847%3AC ...

  10. 深入理解JVM——关于垃圾回收

    关于垃圾回收 仿佛来自上海居委会大妈的灵魂拷问:“你是什么垃圾?” 不 今天我们要说的是JVM的垃圾回收 假如我是一个“人”类的“对象”,也和人的生命一样必有一死,可是“我真的还想再活500年~~”, ...