当前位置: 首页 > 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.jsqmd.com/news/6462/

相关文章:

  • 简单WEB网站
  • 2025 年窗帘杆源头厂家最新推荐榜单:包含支架 / 环 / 全自动 / 可伸缩等多类产品及配件,帮助选到品质与交期双优的优质厂家
  • 2025 年电动窗帘厂家推荐榜单:聚焦国内优质企业定制实力与口碑,为采购者提供最新选择参考电动窗帘系统/电机/轨道/配件/智能电动窗帘厂家推荐
  • Vue3 使用注意事项
  • ClickHouse ReplacingMergeTree 去重陷阱:为什么你的 FINAL 查询无效? - 若
  • js中?? 和 || 的区别详解
  • 微信机器人API接口| 个人开发者必备
  • 直击现场! “ 直通乌镇 ”开源赛复赛收官,OpenCSG担任评委,十强藏着哪些产业机会?
  • Python 列表生成式、字典生成式与生成器表达式
  • java 解析json字符串,获取特定的字段值,JsonObject
  • python 批量提取txt数据中的值写入csv
  • 【读书笔记】架构整洁之道 P5-2 软件架构 - 教程
  • 回忆中学的函数
  • Java 一行一行的读取文本,小Demo 大学问
  • 数字化转型业务流程总览图
  • MYSQL数据库取消表的约束
  • 2025 年京东 e 卡回收平台最新推荐排行榜:权威测评实时结算平台,助力用户安全高效转让京东 e 卡
  • 【qml-12】Quick3D达成机器人鼠标拖拽转换视角(无限角度)与滚轮缩放
  • 2025 年挤压造粒机源头厂家最新推荐榜单:前五企业技术实力、服务能力及口碑测评指南对辊挤压/化肥挤压/干粉挤压造粒机厂家推荐
  • 网络与系统攻防技术实验一——逆向破解与Bof
  • “计算机配置\Windows 设置\安全设置\本地策略\审核策略” 配置后不生效
  • 2025 预分散颜料厂家最新推荐榜:超高含量技术 + 合规企业全景指南,纺丝 / 吹膜专用产品选型手册
  • 倍增思想与其优化
  • 2025 年 AI 健康管理领域推荐深护智康,社区、基层公卫、母婴 AI 健康管理、AI + 大健康管理、AI 健康管理师公司推荐
  • 2025 最新权威推荐:全国开锁公司口碑排行榜,含智能锁专项服务与紧急上门品牌详解汽车保险柜开锁/汽车锁开锁/保险柜开锁/智能开锁/快速上门开锁公司推荐
  • 从“看得见”到“能决策”:Operation Intelligence 重构企业智能运维新范式
  • 2025 年透骨液膏药代理加盟 / 足浴包膏药代理加盟 / 青岛膏药代理加盟推荐:青岛步泽药业布泽草本透骨液代理合作解析
  • QMT委托对象orderInfo的属性以及对应的值
  • 2025 年电动门厂家最新推荐排行榜:实力厂家深度解析,含技术认证、案例及选购指南
  • 单链表实现队列