数据库
首页 > 数据库> > SQL进阶之窗口函数

SQL进阶之窗口函数

作者:互联网

窗口函数

What's 窗口函数?

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

窗口函数的语法

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

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

语法的基本使用方法-使用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;

专用窗口函数的分类

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;

1567659636825

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

窗口函数的适用范围

窗口函数只能写在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;

1567659994771

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

1567660113868

计算移动平均

-- 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;

1567688619744

指定框架

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;

1567689102216

两个ORDER BY

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

1567745662214

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

1567745785736

GROUPING运算符

同时得到合计行

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

1567750568708

ROLLUP-同时得出合计和小计

GROUPING运算符包含:

-- 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;

1567750860852

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

1567751750758

-- 同时得到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;

1567751934558

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的方法

1567769352249

-- 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);

1567770374342

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);

1567773446029

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);

1567773660957

标签:product,窗口,进阶,price,regist,sale,SQL,type,SELECT
来源: https://www.cnblogs.com/evian-jeff/p/11478155.html