如何在SQL中不插入数据、不使用DDL/DML生成动态分组行
实现方案(全程仅用SELECT查询,无DDL/DML操作)
核心逻辑是通过窗口函数给原结果加行号、生成分组标识,再合并动态生成的Parent行后排序输出,完全不需要修改表结构或写入数据。
通用实现步骤
- 第一步:给原查询的所有结果按你需要的排序规则生成连续行号
- 第二步:根据行号计算分组编号(每150行1组,分组号 = CEIL(行号/150))
- 第三步:生成所有Parent行,每行对应一个分组
- 第四步:合并原数据行与Parent行,按分组号、行类型(Parent行优先)、原行号排序,得到最终结果
代码示例(以MySQL 8.0+为例,其他数据库语法仅窗口函数部分略有差异)
假设你原本的查询语句为 SELECT value, name FROM your_source_table ORDER BY value,修改后的查询如下:
WITH original_result AS ( -- 这里替换成你原本的查询逻辑,同时生成行号 SELECT value, name, ROW_NUMBER() OVER (ORDER BY value) AS row_num -- ORDER BY 保持和你原查询的排序规则一致 FROM your_source_table ), group_info AS ( -- 计算总分组数,用于生成Parent行 SELECT CEIL(MAX(row_num)/150) AS total_group FROM original_result ), parent_rows AS ( -- 动态生成所有Parent行 SELECT CONCAT('Parent', seq) AS value, CONCAT('Parent ', seq) AS name, seq AS group_id, 0 AS sort_flag -- 排序标识,保证Parent行在同组最前面 FROM ( -- 生成1到total_group的连续序列,不同数据库生成序列的方式可自行调整 WITH RECURSIVE seq_gen AS ( SELECT 1 AS seq UNION ALL SELECT seq + 1 FROM seq_gen, group_info WHERE seq < group_info.total_group ) SELECT seq FROM seq_gen ) t ), data_rows AS ( -- 给原数据行加上分组和排序标识 SELECT value, name, CEIL(row_num/150) AS group_id, 1 AS sort_flag, row_num FROM original_result ) -- 合并两类行并排序输出 SELECT value, name FROM ( SELECT value, name, group_id, sort_flag, row_num FROM parent_rows UNION ALL SELECT value, name, group_id, sort_flag, row_num FROM data_rows ) t ORDER BY group_id, sort_flag, row_num;
不同数据库适配说明
- PostgreSQL:序列生成可直接用
generate_series(1, (SELECT CEIL(MAX(row_num)/150) FROM original_result))替代递归CTE - SQL Server:窗口函数语法和递归CTE和上述示例一致,无需大改
- 老版本MySQL(5.x不支持CTE):可通过用户变量实现行号计算,再用UNION拼接Parent行即可
注意:如果需要调整每组的行数,直接把代码里的150改成你需要的数值即可。
内容的提问来源于stack exchange,提问作者Chris Pop
相关产品推荐
相关产品推荐

