窗口函数

What's 窗口函数?

窗口函数也称为OLAP(OnLine Analytical Processing)函数,目前MySQL还不支持。

窗口函数的语法

<窗口函数> OVER ([PARTITION BY <列清单>] ORDER BY <排列用列清单>)

能够作为窗口函数使用的函数

  • 能够作为窗口函数的聚合函数(SUM、AVG、COUNT、MAX、MIN)
  • RANK、DENSE_RANK、ROW_NUMBER等专用窗口函数

语法的基本使用方法-使用RANK函数

-- 使用PARTITION BY进行分组
SELECT product_name,product_type,sale_price,RANK() OVER (PARTITION BY product_type ORDER BY sale_price) AS ranking FROM Product;

窗口函数兼具GROUP BY的分组功能及ORDER BY的排序功能,通过PARTITION BY分组后的记录集合称为窗口

无需指定PARTITION BY

-- 将全部数据作为一个组
SELECT product_name,product_type,sale_price,RANK() OVER (ORDER BY sale_price) AS ranking FROM Product;

专用窗口函数的分类

  • RANK函数

    计算排序时存在相同的位次,则会跳过之后的位次(1/1/1/4)

  • DENSE_RANK函数

    计算排序时存在相同位次的记录,也不跳过之后的位次(1/1/1/2)

  • ROW_NUMBER函数

    赋予唯一的连续位次(1/2/3/4)

SELECT product_name,product_type,sale_price,
RANK () OVER (ORDER BY sale_price) AS ranking,
DENSE_RANK () OVER (ORDER BY sale_price) AS dense_ranking,
ROW_NUMBER () OVER (ORDER BY sale_price) AS row_num
FROM Product;

专用窗口函数无需参数,因此通常括号中都是空的

窗口函数的适用范围

窗口函数只能写在SELECT子句的位置,原因在于:窗口函数是对WHERE过滤和GROUP BY分组之后的结果进行的操作,所以在SELECT子句以外的位置"使用窗口函数"是没有意义的。

作为窗口函数的聚合函数

-- 求累计和
SELECT product_id,product_name,sale_price,
SUM(sale_price) OVER (ORDER BY product_id) AS current_sum
FROM Product;

-- 求累计和/累计计数
SELECT product_id,product_name,sale_price,
AVG(sale_price) OVER (ORDER BY product_id) AS current_avg
FROM Product;

计算移动平均

-- moving average
SELECT product_id,product_name,sale_price,
AVG(sale_price) OVER (ORDER BY product_id ROWS 2 PRECEDING) AS moving_avg
FROM Product;

指定框架

  • ROWS+PROCEDING两个关键字,将框架指定为截止到之前~行
  • FOLLOWING关键词可以指定截止到之后~行。
  • 同时使用PRECEDING和FOLLOWING关键字,将当前记录的前后行作为汇总对象
SELECT product_id,product_name,sale_price,
AVG(sale_price) OVER (ORDER BY product_id
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS moving_avg
FROM Product;

两个ORDER BY

-- 窗口函数中的ORDER BY并不能保证最终结果的排序顺序,下图纯属巧合
SELECT product_name,product_type,sale_price,
RANK() OVER (ORDER BY sale_price) AS ranking
FROM Product;

-- 在SELECT后使用ORDER BY子句可以对结果进行排序
SELECT product_name,product_type,sale_price,
RANK() OVER (ORDER BY sale_price) AS ranking
FROM Product ORDER BY ranking;

GROUPING运算符

  • why? 只使用GROUP BY子句和聚合函数是无法同时得到小计和合计的。要解决这一问题,得使用GROUPING运算符。
  • 理解GROUPING运算符中CUBE的关键在于形成"积木搭建出的立方体"的印象。
  • 虽然GROUPING运算符是标准SQL的功能,但部分DBMS尚未支持这一功能。

同时得到合计行

-- 不是用GROUPING如何实现? union 缺点:无法保证总计行的顺序
SELECT '总计' AS product_type,SUM(sale_price) FROM Product
UNION
SELECT product_type,SUM(sale_price) FROM Product GROUP BY product_type;

ROLLUP-同时得出合计和小计

GROUPING运算符包含:

  • ROLLUP
  • CUBE
  • GROUPING SETS
-- Oracle/SQL Sever/DB2/PostgreSQL
SELECT product_type,SUM(sale_price) AS sum_price
FROM Product
GROUP BY ROLLUP(product_type);
-- MySQL
SELECT product_type,SUM(sale_price) AS sum_price
FROM Product
GROUP BY product_type WITH ROLLUP;

SELECT product_type,regist_date,SUM(sale_price) AS sum_price
FROM Product
GROUP BY product_type,regist_date;

-- 同时得到ROLLUP的总计和product_type中个值的小计
-- Oracle/SQL Sever/DB2/PostgreSQL
SELECT product_type,regist_date,SUM(sale_price) AS sum_price
FROM Product
GROUP BY ROLLUP(product_type,regist_date);
-- MySQL
SELECT product_type,regist_date,SUM(sale_price) AS sum_price
FROM Product
GROUP BY product_type,regist_date WITH ROLLUP;

GROUPING函数-让NULL更容易分辨

-- Oracle/SQL Sever/DB2/PostgreSQL
SELECT GROUPING(product_type) AS product_type,
GROUPING(regist_date) AS regist_date,SUM(sale_price) AS sum_price
FROM Product
GROUP BY ROLLUP(product_type,regist_date);
-- 注意碰到超级分组记录中的NULL时返回1,原始数据为NULL时返回0,这是分辨超级分组记录中的NULL和原始数据中的NULL的方法

-- Oracle/SQL Sever/DB2/PostgreSQL
SELECT CASE WHEN GROUPING(product_type) = 1
THEN '商品种类合计'
ELSE product_type END AS product_type,
CASE WHEN GROUPING(regist_date) = 1
THEN '登记日期合计'
ELSE CAST(regist_date AS VARCHAR(16)) END AS regist_date,
SUM(sale_price) AS sum_price,
COUNT(regist_date)
FROM Product
GROUP BY ROLLUP(product_type,regist_date);

CUBE-用数据搭积木

-- Oracle/SQL Sever/DB2/PostgreSQL
SELECT CASE WHEN GROUPING(product_type) = 1
THEN '商品种类合计'
ELSE product_type END AS product_type,
CASE WHEN GROUPING(regist_date) = 1
THEN '登记日期合计'
ELSE CAST(regist_date AS VARCHAR(16)) END AS regist_date,
SUM(sale_price) AS sum_price
FROM Product
GROUP BY CUBE(product_type,regist_date);

GROUPING SETS - 取得期望的积木

-- Oracle/SQL Sever/DB2/PostgreSQL
SELECT CASE WHEN GROUPING(product_type) = 1
THEN '商品种类 合计'
ELSE product_type END AS product_type,
CASE WHEN GROUPING(regist_date) = 1
THEN '登记日期 合计'
ELSE CAST(regist_date AS VARCHAR(16)) END AS regist_date,
SUM(sale_price) AS sum_price
FROM Product
GROUP BY GROUPING SETS (product_type,regist_date);

SQL进阶系列之0窗口函数的更多相关文章

  1. 【 D3.js 进阶系列 — 4.0 】 绘制箭头

    转自:http://www.ourd3js.com/wordpress/?p=660 [ D3.js 进阶系列 — 4.0 ] 绘制箭头 发表于2014/12/08 在 SVG 绘制区域中作图,在绘制 ...

  2. SQL进阶系列之11让SQL飞起来

    写在前面 SQL的性能优化是数据库使用者必须面对的重要问题,本节侧重SQL写法上的优化,SQL的性能同时还受到具体数据库的功能特点影响,这些不在本节讨论范围之内 使用高效的查询 参数是子查询时,使用E ...

  3. SQL进阶系列之7用SQL进行集合运算

    写在前面 集合论是SQL语言的根基,因为这种特性,SQL也被称为面向集合语言 导入篇:集合运算的几个注意事项 注意事项1:SQL能操作具有重复行的集合(multiset.bag),可以通过可选项ALL ...

  4. SQL进阶系列之6用关联子查询比较行与行

    写在前面 使用SQL对同一行数据进行列间的比较很简单,只需要在WHERE子句里写上比较条件就可以了,对于不同行数据进行列间比较需要使用自关联子查询. 增长.减少.维持现状 需要用到行间比较的经典场景是 ...

  5. Linq To Sql进阶系列(六)用object的动态查询与保存log篇

    动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处.而Linq的推出,是为了弥补编程中的 Data != Object 的问题.我们又该如何实现用object的动 ...

  6. 【 D3.js 进阶系列 — 1.0 】 CSV 表格文件的读取

    在入门系列的教程中.我们经常使用 d3.json() 函数来读取 json 格式的文件.json 格式非常强大.但对于普通用户可能不太适合,普通用户更喜欢的是用 Microsoft Excel 或 O ...

  7. SQL进阶系列之10HAVING子句又回来了

    写在前面 HAVING子句的处理对象是集合而不是记录 各队,全队点名 --各队,全体点名! CREATE TABLE Teams (member CHAR(12) NOT NULL PRIMARY K ...

  8. SQL进阶系列之9用SQL处理数列

    写在前面 关系模型的数据结构里,并没有顺序的概念,但SQL处理有序集合也有坚实的理论基础 生成连续编号 --生成连续编号 CREATE TABLE Digits (digit INTEGER PRIM ...

  9. SQL进阶系列之8EXISTS谓词的用法

    写在前面 支撑SQL和关系数据库的基础理论:数学领域的集合论和逻辑学标准体系的谓词逻辑 理论篇 什么是谓词?谓词是返回值为真值(true false unknown)的函数 关系数据库里,每一个行数据 ...

随机推荐

  1. [简短问答]SET_PRINT_STYLEA相关简短问答

    常见1:SET_PRINT_STYLEA(0,.....)放在那里参考官网下载中心的LODOP技术手册SET_PRINT_STYLEA篇,0代表前面紧跟着的打印项,放在需要该样式的打印项后面紧跟着. ...

  2. 扩展Redis的Jedis客户端,哨兵模式读请求走Slave集群

    原 扩展Redis的Jedis客户端,哨兵模式读请求走Slave集群 2018年12月06日 14:26:45 温故而知新666 阅读数 897   版权声明:本文为博主原创文章,遵循CC 4.0 b ...

  3. kubernetes之secret

    Secret解决了密码.token.密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中.Secret可以以Volume或者环境变量的方式使用. Secret类型: Opa ...

  4. 【Luogu P2765】魔术球问题

    Luogu P2765 一开始看到这道题完全想不到怎么做,绞尽脑汁也想不到怎么去构造这个网络流模型. 于是查看了多篇题解--学习了多篇题解的讲解,终于找到了思路. 本文参考了洛谷 这一道题的题意并不难 ...

  5. LeetCode 103. 二叉树的锯齿形层次遍历(Binary Tree Zigzag Level Order Traversal)

    103. 二叉树的锯齿形层次遍历 103. Binary Tree Zigzag Level Order Traversal 题目描述 给定一个二叉树,返回其节点值的锯齿形层次遍历.(即先从左往右,再 ...

  6. 【LeetCode】四数之和【排序,固定k1,k2,二分寻找k3和k4】

    给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满 ...

  7. 完全卸载MySQL服务

    1.控制面板——>所有控制面板项——>程序和功能,卸载mysql server! 2.删除MySQL文件,尤其是ProgramData里面的隐藏文件MySQL,我当时没有删除,重新安装My ...

  8. Java开发笔记(一百一十六)采用UDP协议的Socket通信

    前面介绍了如何通过Socket接口传输文本与文件,在示例代码中,Socket客户端得先调用connect方法连接服务端,确认双方成功连上后才能继续运行后面的代码,这种确认机制确保客户端与服务端的的确确 ...

  9. MySQL Group Replication的安装部署

    一.简介 这次给大家介绍下MySQL官方最新版本5.7.17中GA的新功能 Group Replication . Group Replication是一种可用于实现容错系统的技术.复制组是一组通过消 ...

  10. Kubernetes1.11.1 使用Nvidia显卡配置方法

    一.安装 1.1.kubernetes硬件支持问题说明 Kubernetes目前主要在很小程度上支持CPU和内存的发现.Kubelet本身处理的设备非常少.Kubernetes对于硬件都使用都依赖于硬 ...