何小豆儿在此 发表于 2024-8-31 09:17:32

MySQL窗口函数详解

MySQL窗口函数详解

MySQL从8.0版本开始引入了窗口函数,这是一个强大的特性,可以大大简化复杂的数据分析使命。本文将详细介绍MySQL窗口函数的概念、语法和常见用法,并联合实际应用场景举行阐明。
什么是窗口函数?

窗口函数是一种可以或许对结果集中的一组行举行操作的函数。它们类似于聚合函数,但不会将结果集缩减为单个行 - 相反,它们为每一行返回一个结果。
窗口函数的语法

基本语法如下:
function_name() OVER (
   
   
   
)


[*]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;
这个查询首先为每个部门的员工按薪资举行排名,然后筛选出排名前三的员工。
https://i-blog.csdnimg.cn/direct/38f3f950cd7947b894e8aa50e177ffab.png
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() 不会。
https://i-blog.csdnimg.cn/direct/5757bb38b6cf4a96913787e87f6aaa91.png
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;
这个查询计算了每个月的贩卖额相比客岁同期的增长率。
https://i-blog.csdnimg.cn/direct/f8c4d07d47404c42977943c3b26893d1.png
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;
这个查询计算了每个部门的累计贩卖额,按日期排序。
https://i-blog.csdnimg.cn/direct/11dd8e72d72a46a3b8cf44f59f7fab41.png
实际应用场景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天的移动匀称价格。
https://i-blog.csdnimg.cn/direct/e0aeaed7d8994d0b817c5739791449f7.png
结论

窗口函数是MySQL 8.0中的一个强大新特性,可以大大简化复杂的数据分析使命。通过上述实际应用场景的例子,我们可以看到窗口函数在处置处罚排名、时间序列数据、累计计算等方面的强大本领。这些函数使得我们可以或许更高效地处置处罚诸如员工排名、同比增长、累计总和、移动匀称等常见的数据分析问题。
随着对窗口函数的深入明确和熟练应用,你将可以或许编写更简洁、更高效的SQL查询,大大提高数据分析的效率。窗口函数不但可以简化查询,还可以提高查询性能,由于它们通常比使用子查询或自毗连的等效查询更有效率。
继承探索和实践这些窗口函数,你会发现它们在一样平常数据分析工作中的无穷潜力。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: MySQL窗口函数详解