MySQL 8.0 带来了许多新特性和改进,这些改进可以显著提升数据库的性能、安全性和易用性。以下是一些 MySQL 8.0 特性的使用案例 ,适用于 MySQL 8.0 以及更高版本。
1、 窗口函数
窗口函数的作用类似于在查询中对数据进行分组,不同的是,分组操作会把分组的结果聚合成一条记录,而窗口函数是将结果置于每一条数据记录中。
窗口函数的语法结构是:
函数 OVER ( [PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC] )
或者
函数 OVER 窗口名 … WINDOW 窗口名 AS ( [PARTITION BY 字段名 ORDER BY 字段名 ASC|DESC] )
函数,这里可以是我们之前已经学过的聚合函数,比如( COUNT(), SUM(), AVG() 等)。也可以是其他函数,比如 ranking 排序函数,分析函数等。
OVER 关键字指定函数窗口的范围。
如果省略后面括号中的内容,则窗口会包含满足 WHERE 条件的所有记录,窗口函数会基于所有满足 WHERE 条件的记录进行计算。
如果 OVER 关键字后面的括号不为空,则可以使用如下语法设置窗口。
窗口名:为窗口设置一个别名,用来标识窗口。
PARTITION BY 子句:指定窗口函数按照哪些字段进行分组。分组后,窗口函数可以在每个分组中分别执行。
ORDER BY 子句:指定窗口函数按照哪些字段进行排序。执行排序操作使窗口函数按照排序后的数据记录的顺序进行编号。
FRAME 子句:为分区中的某个子集定义规则,可以用来作为滑动窗口使用。
( 1 )、求平均数
求所有员工姓名、员工工资以及所有员工的平均薪资
# 不使用窗口函数 select e1.emp_name, e1.sal, e2.avg_sal from employee_sal e1 inner join (select avg(sal) avg_sal from employee_sal) e2;
# 使用窗口函数【 MySQL8.0+ 】 select e1.emp_name,e1.sal,avg(e1.sal) over() as avg_salary from employee_sal e1;
( 2 )求总和
员工姓名、员工工资以及公司薪资总支出
# 不使用窗口函数 select e1.emp_name, e1.sal, e2.sum_sal from employee_sal e1 inner join (select sum(sal) sum_sal from employee_sal) e2;
# 使用窗口函数【 MySQL8.0+ 】 select e1.emp_name, e1.sal, sum(e1.sal) over() as sum_salary from employee_sal e1;
( 3 )、 ROW_NUMBER() 序号函数
能够对数据中的序号进行顺序显示。
举例:查询 goods 数据表中每个商品分类下价格降序排列的各个商品信息。 SELECT ROW_NUMBER() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num, id, category_id, category, NAME, price, stock FROM goods;

( 4 )、序号排序函数
RANK() 函数
对序号进行并列排序,并且会跳过重复的序号,比如序号为 1 、 1 、 3 。
DENSE_RANK() 函数
对序号进行并列排序,并且不会跳过重复的序号,比如序号为 1 、 1 、 2 。
在名称为 “女装 / 女士精品”的商品类别中,有两款商品的价格为 89.90 元,分别是卫衣和牛仔裤。
两款商品的序号都应该为 2 ,而不是一个为 2 ,另一个为 3 。 类似考试成绩排名
此时,可以使用
RANK()
函数和
DENSE_RANK()
函数解决。
SELECT RANK() OVER(PARTITION BY category_id ORDER BY price DESC) AS row_num,
id, category_id, category, NAME, price, stock
FROM goods;

( 5 )、前后函数
LAG(expr,n) 函数
返回当前行的前 n 行的 expr 的值。
LEAD(expr,n) 函数
LEAD(expr,n) 函数返回当前行的后 n 行的 expr 的值。
举例:查询 goods 数据表中前一个商品价格与当前商品价格的差值。 SELECT id, category, NAME, price, LAG(price,1) OVER (PARTITION BY category_id ORDER BY price) AS pre_price, price - LAG(price,1) OVER (PARTITION BY category_id ORDER BY price) as diff_price FROM goods;
或 SELECT id, category, NAME, price, LAG(price,1) OVER w AS pre_price, price - LAG(price,1) OVER w as diff_price FROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price);

按照价格降序排序,查询第 1 个商品的价格信息。并且当价格在 400 元内,定义为低价商品;价格在 400-1000 元,定义为中价商品; 1000 元以上定义为高价商品。 SELECT id, category, NAME, price, stock, FIRST_VALUE(price) OVER w AS first_price, (CASE WHEN price < 400 THEN ' 低价商品 ' WHEN price >= 400 AND price < 1000 THEN ' 中价商品 ' ELSE ' 高价商品 ' END) AS 商品价格等级 FROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price desc);

( 6 )、首尾函数
FIRST_VALUE(expr) 函数
返回第一个 expr 的值。
LAST_VALUE(expr) 函数
返回最后一个 expr 的值。
案例
按照价格排序,查询第 1 个商品的价格信息。降序 desc SELECT id, category, NAME, price, stock,FIRST_VALUE(price) OVER w AS first_price FROM goods WINDOW w AS (PARTITION BY category_id ORDER BY price);
