Hive SQL 窗口函数 `ROW_NUMBER() ` 案例分析

一文彻底搞懂 ROW_NUMBER() 和 PARTITION BY

1. 引言

在处理大规模数据集时,Hive SQL 提供了强大的窗口函数(Window Function),如 ROW_NUMBER(),用于为结果集中的每一行分配唯一的行号。当与 PARTITION BYORDER BY 结合使用时,ROW_NUMBER() 可以帮助解决许多复杂的分析任务,例如去重、排名和分页查询等。本文将详细介绍如何结合这三个元素来实现高效的SQL查询。

2. 语法结构

2.1 ROW_NUMBER()
  • 定义:为分区内的每一行分配一个唯一的行号。

  • 用法

    sql 复制代码
    ROW_NUMBER() OVER ([PARTITION BY <expr_list>] ORDER BY <expr_list>)
2.2 PARTITION BY
  • 作用:定义了窗口函数应用于哪些逻辑分组或分区。
  • 字段意义:指定用来分组的列,所有具有相同值的行会被归入同一组。
  • 示例PARTITION BY department_id 表示按部门ID分组。
2.3 ORDER BY
  • 作用:确定行号分配的顺序。
  • 字段意义 :定义排序规则,可以是一个或多个字段,并可指定升序 (ASC) 或降序 (DESC)。
  • 示例ORDER BY salary DESC 按薪资从高到低排序。

3. 使用场景与实际案例

为了更好地展示 ROW_NUMBER() 结合 PARTITION BYORDER BY 的使用方法,还是要 show case 的,下面通过具体 🌰 来解释如何在不同的业务需求下应用这些功能。

3.1 数据去重

在某些情况下,数据集中可能存在重复记录,而我们只希望保留特定条件下的一条记录(如最新的记录)。这时可以使用 ROW_NUMBER() 来为每组记录分配行号,并选择行号为1的记录以达到去重的目的。

案例1:最新交易记录(按客户)
考虑一张名为 transactions 的表,包含以下字段:

  • trans_id: 交易ID
  • customer_id: 客户ID
  • amount: 交易金额
  • transaction_date: 交易日期
    需求:找出每位客户的最近一次交易记录。

具体操作如下:

sql 复制代码
WITH LatestTransactions AS (
  SELECT 
    trans_id,
    customer_id,
    amount,
    transaction_date,
    ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY transaction_date DESC) as rn
  FROM transactions
)
SELECT 
  trans_id,
  customer_id,
  amount,
  transaction_date
FROM LatestTransactions
WHERE rn = 1;
  • 解释PARTITION BY customer_id 把所有交易按照客户分组;ORDER BY transaction_date DESC 确保每组内的交易按时间降序排列,因此最新的交易会获得行号1。

3.2 获取排名

当需要根据某个标准对数据进行排序并计算相对排名时,比如找出每个月销售额最高的前N名销售员或每个部门内薪资最高的员工,可以利用 ROW_NUMBER() 函数结合 PARTITION BYORDER BY 来实现。

案例2:员工薪资排名(按部门)
假设有一个名为 employees 的表,包含以下字段:

  • emp_id: 员工ID
  • name: 员工姓名
  • department_id: 部门ID
  • salary: 薪资
    需求:为每个部门的员工按照薪资从高到低排序,并给出他们的排名。

具体操作如下:

sql 复制代码
WITH EmployeeRank AS (
  SELECT 
    emp_id,
    name,
    department_id,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY salary DESC) as rank
  FROM employees
)
SELECT 
  emp_id,
  name,
  department_id,
  salary,
  rank
FROM EmployeeRank;
  • 解释PARTITION BY department_id 将数据分为不同部门的组;ORDER BY salary DESC 在每个部门内根据薪资从高到低排序。
    案例3:月度销售冠军(按产品类别)
    假设有如下表格 sales,包含以下字段:

  • sale_id: 销售记录ID

  • product_category: 产品类别

  • salesperson: 销售人员名字

  • sales_amount: 销售金额

  • month: 月份
    需求:计算每个月每个产品类别的销售冠军。

具体操作如下:

sql 复制代码
WITH MonthlySalesLeaders AS (
  SELECT 
    product_category,
    salesperson,
    month,
    sales_amount,
    ROW_NUMBER() OVER (PARTITION BY product_category, month ORDER BY sales_amount DESC) as rank
  FROM sales
)
SELECT 
  product_category,
  salesperson,
  month,
  sales_amount
FROM MonthlySalesLeaders
WHERE rank = 1;
  • 解释PARTITION BY product_category, month 创建了基于产品类别和月份的分区;ORDER BY sales_amount DESC 确保了每个分区内销售额最高的销售人员会被排在最前面。

3.3 分页查询

当处理大量数据时,可能需要分批次地展示结果集。例如,在网页上显示搜索结果时,通常每次只加载一部分数据。此时,可以通过 ROW_NUMBER() 来实现分页效果。

案例4:获取第101到200条记录

  • 假设你有一个大表 large_table,并且想要获取该表中第101到200条记录(假设表中有一列 id 可以用来排序)。

具体操作如下:

sql 复制代码
WITH PaginatedData AS (
  SELECT 
    *,
    ROW_NUMBER() OVER (ORDER BY id) as row_num
  FROM large_table
)
SELECT *
FROM PaginatedData
WHERE row_num BETWEEN 101 AND 200;
  • 解释 :这里使用 ROW_NUMBER() 为每一行分配一个唯一的行号,并通过 WHERE 子句筛选出所需的分页范围。

通过上述场景和对应的案例,可以看到 ROW_NUMBER() 结合 PARTITION BYORDER BY 是多么强大且灵活。它不仅能够解决常见的数据分析问题,还能提高查询效率,使得复杂的数据处理变得更加直观和简便。

相关推荐
笨蛋少年派7 分钟前
大数据集群环境搭建(Ubantu)
大数据
Elastic 中国社区官方博客9 分钟前
在 Elasticsearch 中改进 Agentic AI 工具的实验
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
云雾J视界13 分钟前
Flink Checkpoint与反压问题排查手册:从日志分析到根因定位
大数据·阿里云·flink·linq·checkpoint·反压
豆沙沙包?19 分钟前
2025年--Lc172--H178 .分数排名(SQL)--Java版
数据库·sql
AI数据皮皮侠27 分钟前
中国地级市旅游人数、收入数据(2000-2023年)
大数据·人工智能·python·深度学习·机器学习·旅游
2301_772093561 小时前
tuchuang_myfiles&&share文件列表_共享文件
大数据·前端·javascript·数据库·redis·分布式·缓存
K_i1341 小时前
电信大数据实战:MySQL与Hadoop高效同步
大数据·hadoop·mysql
sensen_kiss1 小时前
INT305 Machine Learning 机器学习 Pt.3二元分类和多类分类
大数据·机器学习·分类
B站计算机毕业设计之家7 小时前
智慧交通项目:Python+PySide6 车辆检测系统 YOLOv8+OpenCV 自定义视频 自定义检测区域 (源码+文档)✅
大数据·python·opencv·yolo·智慧交通·交通·车流量
数据与人工智能律师8 小时前
AI的法治迷宫:技术层、模型层、应用层的法律痛点
大数据·网络·人工智能·云计算·区块链