当前位置: 首页 > news >正文

ClickHouse 窗口函数详解:告别 GROUP BY 的局限性,实现灵活数据分析 - 若

什么是窗口函数?

窗口函数是 SQL 中一种强大的分析功能,它允许在对每一行进行计算时,能够访问到与当前行相关的多行数据。与 GROUP BY 不同,窗口函数不会将多行合并为一行,而是保留所有原始行,同时添加计算列。

直观理解

想象一个 Excel 表格:

 
 
姓名 部门 工资
张三 技术部 8000
李四 技术部 9000
王五 技术部 7500
赵六 销售部 7000

普通 GROUP BY:

sql
SELECT 部门, AVG(工资) as 平均工资 FROM 员工表 GROUP BY 部门;

结果:2行数据(部门聚合结果)

窗口函数:

sql
SELECT 姓名, 部门, 工资, AVG(工资) OVER (PARTITION BY 部门) as 部门平均工资 FROM 员工表;

结果:4行数据(保留所有原始行,新增计算列)

窗口函数的核心概念

1. 窗口定义

sql
函数名() OVER (PARTITION BY 分组字段ORDER BY 排序字段[窗口帧]
)
  • PARTITION BY:将数据分成多个窗口(类似 GROUP BY)

  • ORDER BY:在窗口内排序

  • 窗口帧:定义计算范围(如前后几行)

2. 常用窗口函数分类

排名函数

sql
-- 为每行分配唯一序号
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rn-- 排名,相同值会有并列
RANK() OVER (PARTITION BY department ORDER BY salary DESC) as rank-- 密集排名,无间隔
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) as dense_rank

聚合函数

sql
-- 窗口内求和
SUM(salary) OVER (PARTITION BY department) as dept_total-- 窗口内平均值
AVG(salary) OVER (PARTITION BY department) as dept_avg-- 窗口内最大值
MAX(salary) OVER (PARTITION BY department) as dept_max

分布函数

sql
-- 百分比排名
PERCENT_RANK() OVER (ORDER BY salary) as pct_rank-- 累计分布
CUME_DIST() OVER (ORDER BY salary) as cume_dist

实战案例:解决数据去重问题

问题场景

在区块链任务表中,每个 (start_block, end_block) 组合可能有多个版本,我们需要获取每个组合的最新版本(created_at 最大的记录)。

传统方案的局限性

sql
-- GROUP BY 无法获取完整记录
SELECT start_block, end_block, MAX(created_at)
FROM block_tasks 
GROUP BY start_block, end_block;

问题:只能返回分组字段和聚合值,无法获取其他字段的完整信息。

窗口函数解决方案

sql
SELECT * FROM (SELECT *,ROW_NUMBER() OVER (PARTITION BY start_block, end_block ORDER BY created_at DESC) as rnFROM block_tasks WHERE status = 'init'
) WHERE rn = 1;

执行过程分解

原始数据:

 
 
id start_block end_block status created_at
1 1000 2000 init 2024-01-01 10:00:00
2 1000 2000 init 2024-01-02 15:00:00
3 1001 2001 init 2024-01-01 09:00:00
4 1001 2001 init 2024-01-03 14:00:00

窗口函数计算后:

 
 
id start_block end_block created_at rn
1 1000 2000 2024-01-01 10:00:00 2
2 1000 2000 2024-01-02 15:00:00 1
3 1001 2001 2024-01-01 09:00:00 3
4 1001 2001 2024-01-03 14:00:00 1
5 1001 2001 2024-01-02 11:00:00 2

最终结果(rn = 1):

 
 
id start_block end_block created_at
2 1000 2000 2024-01-02 15:00:00
4 1001 2001 2024-01-03 14:00:00

更多实用场景

场景1:计算移动平均

sql
-- 计算每行及前2行的平均价格
SELECT date, price,AVG(price) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) as moving_avg
FROM stock_prices;

场景2:计算累计和

sql
-- 计算每月销售额的累计和
SELECT month, sales,SUM(sales) OVER (ORDER BY month ROWS UNBOUNDED PRECEDING) as cumulative_sales
FROM monthly_sales;

场景3:前后行比较

sql
-- 比较当前行与前一行的差异
SELECT date, revenue,LAG(revenue) OVER (ORDER BY date) as prev_revenue,revenue - LAG(revenue) OVER (ORDER BY date) as growth
FROM daily_revenue;

ClickHouse 中的窗口函数

基本语法

sql
function_name([expression]) OVER ([PARTITION BY expression1, expression2, ...][ORDER BY expression1 [ASC|DESC], expression2 [ASC|DESC], ...][frame_specification]
)

性能优化建议

  1. 利用索引:确保 PARTITION BY 和 ORDER BY 的字段有合适索引

  2. 避免全表排序:使用 LIMIT 限制结果集大小

  3. 合理分区:数据分区可以减少单个窗口的数据量

ClickHouse 特定函数

sql
-- 获取每个分组的第一个值
first_value(column) OVER (PARTITION BY group ORDER BY time)-- 获取每个分组的最后一个值  
last_value(column) OVER (PARTITION BY group ORDER BY time)-- 计算分位数
quantile(0.5)(column) OVER (PARTITION BY group)

窗口函数 vs GROUP BY

 
 
特性 GROUP BY 窗口函数
输出行数 分组数量 原始行数
字段访问 只能访问分组字段和聚合值 可以访问所有原始字段
多个聚合 需要多个查询或复杂JOIN 单次查询可计算多个窗口
排序控制 无法控制选择哪条记录 明确指定排序和选择逻辑
性能 通常更快,但信息有限 稍慢,但功能更强大

实际代码示例

Go + GORM 实现

go
func GetLatestTasks(db *gorm.DB) ([]*BlockTask, error) {var tasks []*BlockTasksql := `SELECT * FROM (SELECT *,ROW_NUMBER() OVER (PARTITION BY start_block, end_block ORDER BY created_at DESC) as rnFROM block_tasks WHERE status = 'init') WHERE rn = 1ORDER BY start_block DESCLIMIT 100`err := db.Raw(sql).Scan(&tasks).Errorreturn tasks, err
}

总结

窗口函数是现代 SQL 中不可或缺的强大工具,它解决了 GROUP BY 的诸多限制:

  • ✅ 保留原始数据:不丢失任何行信息

  • ✅ 灵活分析:支持排名、聚合、分布等多种计算

  • ✅ 性能优秀:相比多次查询或复杂 JOIN,通常更高效

  • ✅ 代码简洁:用声明式语法替代复杂的过程逻辑

在数据去重、移动平均、排名计算、趋势分析等场景中,窗口函数都能提供优雅而高效的解决方案。掌握窗口函数,将极大提升你的数据分析能力!

http://www.zskr.cn/news/14301.html

相关文章:

  • Vue3 使用注意事项
  • java 解析json字符串,获取特定的字段值,JsonObject
  • Java 一行一行的读取文本,小Demo 大学问
  • 数字化转型业务流程总览图
  • 2025 年挤压造粒机源头厂家最新推荐榜单:前五企业技术实力、服务能力及口碑测评指南对辊挤压/化肥挤压/干粉挤压造粒机厂家推荐
  • 2025 预分散颜料厂家最新推荐榜:超高含量技术 + 合规企业全景指南,纺丝 / 吹膜专用产品选型手册
  • 2025 最新权威推荐:全国开锁公司口碑排行榜,含智能锁专项服务与紧急上门品牌详解汽车保险柜开锁/汽车锁开锁/保险柜开锁/智能开锁/快速上门开锁公司推荐
  • 2025 年透骨液膏药代理加盟 / 足浴包膏药代理加盟 / 青岛膏药代理加盟推荐:青岛步泽药业布泽草本透骨液代理合作解析
  • 从手机到汽车音响:蚀刻喇叭网的跨界应用前景 - 指南
  • 读人形机器人27太空中
  • 2025 年酒店一次性用品源头厂家最新推荐榜单:含牙签牙线筷子套杯盖等全品类及采购选择指南酒店一次性牙签/牙线/筷子套/杯盖/杯垫/杯套用品 厂家推荐
  • oppoR9m刷Linux系统: 说明-注意事项-知识点
  • 2025阳台装修品牌推荐榜:优质阳台厂商资质、技术、服务测评及高口碑企业优选指南,浙江多为建筑服务与性价比兼具!
  • 2025年杭州软件开发公司最新品牌推荐榜:聚焦技术实力与售后体系的优质服务商精选指南!
  • 【WCH蓝牙系列芯片】-基于CH592开发板——HID_Keyboard中添加读、写、通知的服务属性
  • 快微商城小程序管理系统:助力商家搭建高效便捷的新零售平台
  • KTV 娱乐小程序管理系统:数字化运营新选择,助力行业高效经营
  • 大模型落地实践指南:从技术路径到企业级解决强大的方案
  • 阿里云 CDN 多条件源站配置实战:跨地域环境分流
  • 2025标志牌生产厂家最新推荐排行榜:权威筛选优质标志牌品牌,助您精准选对交通标志牌,反光标志牌,道路标志牌供应商!
  • 2025 年脚手架厂家最新推荐榜:铝合金 / 盘扣 / 快装 / 移动式等多类型产品优选及国内实力企业排行指南
  • 完整教程:大模型浪潮下的“冷思考”:计算机视觉的变局与出路
  • 玳瑁的嵌入式日记---0928(ARM--I2C) - 教程
  • 关于处理大批量数据下载和查询时,怎么进行限流和熔断处理(AI)
  • 这款免费Windows优化神器!只有5M电脑绿色工具!ZyperWin++下载安装教程
  • 深入解析:DAY 04 CSS文本,字体属性以及选择器
  • 泛型类型参数
  • CF1980F2 Field Division (hard version) 题解
  • 天津港口海鲜之旅全攻略(2025最新版)
  • 如何从安卓手机恢复手机照相机消失的相机照片?(6个高效办法)