MySQL窗口函数详解
MySQL从8.0版本开始引入了窗口函数,这是一个强大的特性,可以大大简化复杂的数据分析使命。本文将详细介绍MySQL窗口函数的概念、语法和常见用法,并联合实际应用场景举行阐明。
什么是窗口函数?
窗口函数是一种可以或许对结果集中的一组行举行操作的函数。它们类似于聚合函数,但不会将结果集缩减为单个行 - 相反,它们为每一行返回一个结果。
窗口函数的语法
基本语法如下:
- function_name() OVER (
- [PARTITION BY column_list]
- [ORDER BY column_list]
- [frame_clause]
- )
复制代码
- function_name: 窗口函数的名称
- PARTITION BY: 可选,界说行分组的方式
- ORDER BY: 可选,界说分区老手的排序方式
- frame_clause: 可选,界说当前分区内的行子集(窗口帧)
常用的窗口函数及其应用场景
1. ROW_NUMBER()
ROW_NUMBER() 为每一行分配一个唯一的整数,用于在每个分区内对行举行排序并编号。
可以帮助我们对数据举行分区后排序,获取排名信息。
具体来说,ROW_NUMBER() 是一种分析函数,它可以根据 ORDER BY 子句中指定的列对行举行排序,并为每个分区内的行根据排序结果来分配唯一的连续编号。 PARTITION BY 子句类似于 GROUP BY 用于分组,该子句指定希望分区的列或表达式。行号将在每个分区内分配,然后重新开始为下一个分区分配。
基本用法
- SELECT
- name,
- score,
- ROW_NUMBER() OVER (ORDER BY score DESC) as rank
- FROM students;
复制代码 实际应用场景:查找每个部门的前N名员工
假设我们要找出每个部门薪资最高的3名员工:
- CREATE TABLE employees (
- id INT,
- name VARCHAR(50),
- department VARCHAR(50),
- salary DECIMAL(10, 2)
- );
- INSERT INTO employees (id, name, department, salary) VALUES
- (1, 'Alice', 'Sales', 60000),
- (2, 'Bob', 'Sales', 50000),
- (3, 'Charlie', 'Sales', 55000),
- (4, 'David', 'Marketing', 65000),
- (5, 'Eve', 'Marketing', 60000),
- (6, 'Frank', 'Marketing', 70000),
- (7, 'Grace', 'IT', 80000),
- (8, 'Henry', 'IT', 75000),
- (9, 'Ivy', 'IT', 78000);
- SELECT *
- FROM (
- SELECT
- name,
- department,
- salary,
- ROW_NUMBER() OVER (
- PARTITION BY department
- ORDER BY salary DESC
- ) as salary_rank
- FROM employees
- ) ranked
- WHERE salary_rank <= 3
- ORDER BY department, salary_rank;
复制代码 这个查询首先为每个部门的员工按薪资举行排名,然后筛选出排名前三的员工。
2. RANK() 和 DENSE_RANK()
RANK() 为每一行分配排名,雷同值的行得到雷同排名,但会产生隔断。
DENSE_RANK() 类似于RANK(),但不会产生隔断。
基本用法
- SELECT
- name,
- score,
- RANK() OVER (ORDER BY score DESC) as rank,
- DENSE_RANK() OVER (ORDER BY score DESC) as dense_rank
- FROM students;
复制代码 实际应用场景:学生成绩排名
假设我们要为学生的考试成绩举行排名,同时展示 RANK() 和 DENSE_RANK() 的区别:
- CREATE TABLE student_scores (
- id INT,
- name VARCHAR(50),
- score INT
- );
- INSERT INTO student_scores (id, name, score) VALUES
- (1, 'Alice', 95),
- (2, 'Bob', 95),
- (3, 'Charlie', 90),
- (4, 'David', 88),
- (5, 'Eve', 88),
- (6, 'Frank', 85);
- SELECT
- name,
- score,
- RANK() OVER (ORDER BY score DESC) as rank_number,
- DENSE_RANK() OVER (ORDER BY score DESC) as dense_rank_number
- FROM student_scores;
复制代码 这个查询展示了学生成绩的排名,同时表现了 RANK() 和 DENSE_RANK() 的区别。RANK() 会在雷同分数后产生隔断,而 DENSE_RANK() 不会。
3. LAG() 和 LEAD()
LAG() 和 LEAD() 允许我们访问当前行之前或之后的行。
基本用法
- SELECT
- date,
- sales,
- LAG(sales) OVER (ORDER BY date) as previous_day_sales,
- LEAD(sales) OVER (ORDER BY date) as next_day_sales
- FROM daily_sales;
复制代码 实际应用场景:计算同比增长率
假设我们要计算每月贩卖额的同比增长率:
- CREATE TABLE monthly_sales (
- year INT,
- month INT,
- sales DECIMAL(10, 2)
- );
- INSERT INTO monthly_sales (year, month, sales) VALUES
- (2022, 1, 10000), (2022, 2, 12000), (2022, 3, 15000),
- (2023, 1, 11000), (2023, 2, 13000), (2023, 3, 16000);
- SELECT
- year,
- month,
- sales,
- LAG(sales) OVER (PARTITION BY month ORDER BY year) as prev_year_sales,
- (sales - LAG(sales) OVER (PARTITION BY month ORDER BY year)) /
- LAG(sales) OVER (PARTITION BY month ORDER BY year) * 100 as growth_rate
- FROM monthly_sales
- ORDER BY month, year;
复制代码 这个查询计算了每个月的贩卖额相比客岁同期的增长率。
4. 聚合窗口函数 (如 SUM(), AVG())
聚合函数如 SUM() 和 AVG() 也可以作为窗口函数使用,可以计算累计总和或移动匀称值。
基本用法
- SELECT
- date,
- sales,
- SUM(sales) OVER (ORDER BY date) as cumulative_sales,
- AVG(sales) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as moving_avg
- FROM daily_sales;
复制代码 实际应用场景1:计算累计总和
假设我们要计算每个部门的累计贩卖额:
- CREATE TABLE sales (
- id INT,
- department VARCHAR(50),
- sale_date DATE,
- amount DECIMAL(10, 2)
- );
- INSERT INTO sales (id, department, sale_date, amount) VALUES
- (1, 'Electronics', '2023-01-01', 1000),
- (2, 'Clothing', '2023-01-01', 500),
- (3, 'Electronics', '2023-01-02', 1500),
- (4, 'Clothing', '2023-01-02', 750),
- (5, 'Electronics', '2023-01-03', 1200),
- (6, 'Clothing', '2023-01-03', 600);
- SELECT
- department,
- sale_date,
- amount,
- SUM(amount) OVER (
- PARTITION BY department
- ORDER BY sale_date
- ) as cumulative_sales
- FROM sales
- ORDER BY department, sale_date;
复制代码 这个查询计算了每个部门的累计贩卖额,按日期排序。
实际应用场景2:计算移动匀称值
假设我们有一个股票价格表,我们想计算7天移动匀称价格:
- CREATE TABLE stock_prices (
- date DATE,
- price DECIMAL(10, 2)
- );
- INSERT INTO stock_prices (date, price) VALUES
- ('2023-01-01', 100.00),
- ('2023-01-02', 101.00),
- ('2023-01-03', 102.00),
- ('2023-01-04', 101.50),
- ('2023-01-05', 103.00),
- ('2023-01-06', 104.00),
- ('2023-01-07', 103.50),
- ('2023-01-08', 105.00),
- ('2023-01-09', 106.00),
- ('2023-01-10', 107.00);
- SELECT
- date,
- price,
- AVG(price) OVER (
- ORDER BY date
- ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
- ) AS moving_avg
- FROM stock_prices
- ORDER BY date;
复制代码 这个查询将计算包括当前日期在内的前7天的移动匀称价格。
结论
窗口函数是MySQL 8.0中的一个强大新特性,可以大大简化复杂的数据分析使命。通过上述实际应用场景的例子,我们可以看到窗口函数在处置处罚排名、时间序列数据、累计计算等方面的强大本领。这些函数使得我们可以或许更高效地处置处罚诸如员工排名、同比增长、累计总和、移动匀称等常见的数据分析问题。
随着对窗口函数的深入明确和熟练应用,你将可以或许编写更简洁、更高效的SQL查询,大大提高数据分析的效率。窗口函数不但可以简化查询,还可以提高查询性能,由于它们通常比使用子查询或自毗连的等效查询更有效率。
继承探索和实践这些窗口函数,你会发现它们在一样平常数据分析工作中的无穷潜力。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |