Oracle SQL:按FILE_ID和SEG_NAME求和并保留ROOT_BLID顺序
问题
需要对数据表按连续相同的FILE_ID和SEG_NAME分组,对BYTES列求和,同时保留原表按ROOT_BLID排序的顺序,最终结果不显示ROOT_BLID字段。
原始数据表
FILE_ID SEG_NAME ROOT_BLID BYTES ------- ------------- ---------- ---------- 265 * 128 1048576 265 * 256 1048576 265 * 384 1048576 265 * 512 1048576 265 * 640 1048576 265 * 768 1048576 265 * 896 1048576 265 * 2048 1048576 265 * 2432 1048576 265 * 9856 1048576 265 free 9984 2097152 265 * 10240 134217728 265 * 26624 8388608 265 * 27648 8388608 265 free 29184 1048576 265 * 29312 1048576 265 * 29440 1048576 265 * 29568 1048576 265 SEGMENT_NAME 29696 2097152 265 free 29952 2097152 265 * 30208 8388608 265 * 31232 8388608 265 SEGMENT_NAME 32256 8388608 265 * 33280 8388608 265 SEGMENT_NAME 34304 2634022912 265 SEGMENT_NAME 355840 8388608 265 SEGMENT_NAME 356864 1238368256 265 free 508032 3145728 265 SEGMENT_NAME 508416 805306368 265 SEGMENT_NAME 606720 8388608 265 SEGMENT_NAME 607744 2281701376 265 SEGMENT_NAME 886272 8388608 265 SEGMENT_NAME 887296 1053818880 265 * 1015936 1048576 265 * 1016064 1048576 265 free 1016192 1048576 265 SEGMENT_NAME 1016320 134217728 265 * 1032704 8388608 265 * 1033728 8388608 265 * 1034752 67108864 265 * 1042944 8388608 265 * 1043968 67108864 265 * 1052160 8388608 265 free 1053184 2378170368 61 rows selected.
期望结果
FILE_ID SEG_NAME BYTES ------- ------------- ---------- 265 * 10485760 265 free 2097152 265 * 150994944 265 free 1048576 265 * 3145728 265 SEGMENT_NAME 2097152 265 free 2097152 265 * 16777216 265 SEGMENT_NAME 8388608 265 * 8388608 265 SEGMENT_NAME 3880779776 265 free 3145728 265 SEGMENT_NAME 4157603840 265 * 2097152 265 free 1048576 265 SEGMENT_NAME 134217728 265 * 167772160 265 free 2378170368 18 rows selected.
解决方案
这是典型的连续相同分组聚合场景,不能直接用普通GROUP BY(会合并所有相同SEG_NAME的行),需要先给连续的相同SEG_NAME块分配分组ID,再按分组ID聚合。以下是适用于Oracle的SQL实现:
WITH grouped_data AS ( SELECT FILE_ID, SEG_NAME, BYTES, ROOT_BLID, -- 生成连续分组ID:当SEG_NAME与上一行不同时,分组ID+1 SUM(CASE WHEN SEG_NAME = LAG(SEG_NAME) OVER (PARTITION BY FILE_ID ORDER BY ROOT_BLID) THEN 0 ELSE 1 END) OVER (PARTITION BY FILE_ID ORDER BY ROOT_BLID ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS group_id FROM your_table_name -- 替换为你的实际表名 ) SELECT FILE_ID, SEG_NAME, SUM(BYTES) AS BYTES FROM grouped_data GROUP BY FILE_ID, group_id, SEG_NAME ORDER BY FILE_ID, MIN(ROOT_BLID); -- 按原始ROOT_BLID的顺序排序
逻辑说明
- 生成分组ID:使用窗口函数
LAG获取上一行的SEG_NAME,对比当前行的SEG_NAME,不同则标记为1,相同为0;再用SUM窗口函数累加这些标记,得到每个连续块的唯一group_id。 - 分组聚合:按FILE_ID、group_id、SEG_NAME分组,对BYTES求和。
- 保持原始顺序:按FILE_ID和每个分组的最小ROOT_BLID排序,确保结果顺序和原表一致。
如果是其他数据库(如MySQL 8.0+、PostgreSQL),核心逻辑完全一致,仅需微调语法即可适配。
内容的提问来源于stack exchange,提问作者Seb
相关产品推荐
相关产品推荐

