查询进阶 - 开窗函数 - rank

教程

本节我们来学习一个新的开窗函数 Rank。

Rank 开窗函数是 SQL 中一种用于对查询结果集中的行进行 排名 的开窗函数。它可以根据指定的列或表达式对结果集中的行进行排序,并为每一行分配一个排名。在排名过程中,相同的值将被赋予相同的排名,而不同的值将被赋予不同的排名。

当存在并列(相同排序值)时,Rank 会跳过后续排名,并保留相同的排名。

Rank 开窗函数的常见用法是在查询结果中查找前几名(Top N)或排名最高的行。

Rank 开窗函数的语法如下:

RANK() OVER (
  PARTITION BY 列名1, 列名2, ... -- 可选,用于指定分组列
  ORDER BY 列名3 [ASC|DESC], 列名4 [ASC|DESC], ... -- 用于指定排序列及排序方式
) AS rank_column

其中,PARTITION BY 子句可选,用于指定分组列,将结果集按照指定列进行分组;ORDER BY 子句用于指定排序列及排序方式,决定了计算 Rank 时的排序规则。AS rank_column 用于指定生成的 Rank 排名列的别名。

示例

假设我们有订单表 orders,表格数据如下:

order_idcustomer_idorder_datetotal_amount
11012023-01-01200
21022023-01-05350
31012023-01-10120
41032023-01-15500

现在,我们希望为每个客户的订单按照订单金额降序排名,并显示每个订单的详细信息。

SELECT 
    order_id, 
    customer_id, 
    order_date, 
    total_amount,
    RANK() OVER (PARTITION BY customer_id ORDER BY total_amount DESC) AS customer_rank
FROM
    orders;

查询结果:

order_idcustomer_idorder_datetotal_amountcustomer_rank
11012023-01-012001
31012023-01-101202
21022023-01-053501
41032023-01-155001

在上面的示例中,我们使用开窗函数 RANK 来为每个客户的订单按照订单金额降序排名(customer_rank),并使用 PARTITION BY 子句按照 customer_id 进行分组,并使用 ORDER BY 子句按照 total_amount 从大到小进行排序。

可以看到,开窗函数保留了原始订单的详细信息,同时计算了每个客户的订单金额排名。

题目

假设有一个学生表 student,包含以下字段:id(学号)、name(姓名)、age(年龄)、score(分数)、class_id(班级编号)。

请你编写一个 SQL 查询,返回每个学生的详细信息(字段顺序和原始表的字段顺序一致),并且按照分数降序的方式计算每个班级内的学生的分数排名(ranking)。

SELECT
  id,
  name,
  age,
  score,
  class_id,
  RANK() OVER (
    PARTITION BY
      class_id
    ORDER BY
      score DESC
  ) AS ranking
FROM
  student;

假设有一个学生表 student,包含以下字段:id(学号)、name(姓名)、age(年龄)、score(分数)、class_id(班级编号)。

请你编写一个 SQL 查询,返回每个学生的详细信息(字段顺序和原始表的字段顺序一致),并且按照分数降序的方式计算所有学生的分数排名(ranking)。


SELECT

        id,

        name,

        age,

        score,

        class_id,

        RANK() OVER (

                ORDER BY

                score DESC

        ) AS ranking

FROM student;

<think>好的,我现在需要帮助用户解答关于SQL开窗函数的详细教程和使用示例的问题。首先,我得回忆一下自己对开窗函数的理解,并确保准确。开窗函数,也就是窗口函数,在SQL中用于在查询结果的特定窗口或行集上进行计算,同时保留原有的行数据。这点和聚合函数不同,因为聚合函数通常会将多行合并成一行,而窗口函数不会。 用户可能需要了解基本语法、常用函数以及实际示例。根据提供的引用内容,用户可能已经看过一些基础解释,但需要更详细的教程。引用[2]提到,如果了解聚合函数,就更容易理解开窗函数,所以或许可以从与聚合函数的对比入手。引用[3]中的例子展示了开窗函数与GROUP BY的区别,这也是一个关键点,应该涵盖在回答中。 接下来,我需要整理开窗函数的语法结构。基本语法通常包括OVER子句,其中包含PARTITION BY和ORDER BY,可能还有ROWS子句来定义窗口范围。引用[3]和[4]中的示例可以作为参考,比如使用PARTITION BY对结果集进行分区,ORDER BY在每个分区内排序。 然后,常见的窗口函数有哪些呢?比如ROW_NUMBER(), RANK(), DENSE_RANK()用于排名,SUM(), AVG()等聚合函数作为窗口函数使用,还有LEAD()和LAG()访问前后行的数据。需要为每个函数提供示例,这样用户更容易理解。 实际应用示例部分,可以举几个典型的场景。例如,计算每个班级的平均分,同时保留每个学生的详细信息(如引用[4]中的例子),或者计算销售额的累计总和。这些例子能直观展示开窗函数的优势。 另外,用户可能想知道开窗函数与GROUP BY的区别。引用[3]中的对比示例很有用,需要说明开窗函数如何在不减少行数的情况下提供聚合结果,而GROUP BY会合并行。这有助于用户理解何时使用开窗函数更合适。 最后,用户可能还需要一些进阶内容,比如窗口框架的定义(ROWS BETWEEN ...),或者性能优化的注意事项。但根据用户的问题,可能基础教程和示例更为重要,进阶内容可以放在相关问题里引导用户进一步探索。 需要确保所有示例的LaTeX格式正确,行内公式用$...$,独立公式用$$...$$。同时,回答结构要清晰,分点讲解,每个部分有示例代码,帮助用户逐步理解。引用标记要自然地添加在引用的内容末尾,比如引用[1]提到开窗函数在LeetCode例子中的应用,可以在相关示例后添加引用标识。 现在需要检查是否有遗漏的部分,比如是否涵盖了所有常用的窗口函数,语法是否解释清楚,示例是否足够多样。还要确保回答符合用户的要求:详细教程和使用示例,结构清晰,可靠真实。可能还需要生成相关问题,比如性能优化、与GROUP BY的详细对比等,供用户进一步学习。</think>### SQL开窗函数详解与使用示例 #### 一、基本概念 开窗函数(窗口函数)允许在查询结果的特定窗口(行集合)上执行计算,**同时保留原始行的细节**。与聚合函数(如`SUM()`/`AVG()`)不同,开窗函数不会合并行,而是为每行返回计算结果[^2]。 #### 二、核心语法 ```sql 函数名([参数]) OVER ( PARTITION BY 列1, 列2... -- 分组依据(类似GROUP BY) ORDER BY 列 [ASC|DESC] -- 排序规则 [ROWS BETWEEN 范围] -- 窗口范围(可选) ) ``` #### 三、常用窗口函数 1. **排名函数** - `ROW_NUMBER()`: 生成唯一序号 ```sql SELECT *, ROW_NUMBER() OVER (PARTITION BY ClassName ORDER BY Score DESC) AS 排名 FROM Scores -- 每个班级内按分数降序排名[^4] ``` - `RANK()`: 并列时跳过序号(如1,1,3) - `DENSE_RANK()`: 并列时不跳序号(如1,1,2) 2. **聚合函数** ```sql SELECT ClassName, Score, AVG(Score) OVER (PARTITION BY ClassName) AS 班级平均分, SUM(Score) OVER (ORDER BY Score ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 累计总分 FROM Scores ``` 3. **偏移函数** - `LAG(列, n)`: 获取前n行的值 - `LEAD(列, n)`: 获取后n行的值 #### 四、典型场景示例 **场景1:计算移动平均(窗口框架)** ```sql SELECT 日期, 销售额, AVG(销售额) OVER ( ORDER BY 日期 ROWS BETWEEN 2 PRECEDING AND CURRENT ROW ) AS 三日移动平均 FROM 销售表 ``` 此例计算每行数据及其前两行的平均值,窗口范围会动态变化[^3]。 **场景2:比较同级数据** ```sql SELECT 员工部门, 员工姓名, 工资, LAG(工资) OVER (PARTITION BY 部门 ORDER BY 工资 DESC) AS 上一名工资 FROM 员工表 ``` 显示每个部门内工资排名相邻员工的工资对比[^2]。 #### 五、与GROUP BY的对比 | 特性 | 开窗函数 | GROUP BY | |---------------------|----------------------------|------------------------| | 行数变化 | 保持原行数 | 合并分组 | | 聚合维度 | 可同时显示明细与聚合结果 | 仅显示聚合结果 | | 典型场景 | 排名、累计计算、数据对比 | 汇总统计 | 例如,同时显示学生成绩和班级平均分时: ```sql -- 开窗函数实现 SELECT 姓名, 班级, 分数, AVG(分数) OVER (PARTITION BY 班级) AS 班级平均分 FROM 学生表 -- GROUP BY无法直接实现(需使用JOIN) ``` #### 六、性能优化建议 1. 尽量避免在大数据集上使用`ROWS BETWEEN UNBOUNDED PRECEDING`(全量窗口) 2. 优先使用`PARTITION BY`缩小窗口范围 3. 结合索引优化`ORDER BY`子句的排序效率[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值