如何将含min、max字段的单条数据库记录拆分为区间多条记录?
实现按数值范围生成连续行的SQL方案
问题背景
现有表A的结构与数据如下:
id min max #### #### #### 1 1 3
需要实现类似以下伪SQL的功能,将每行的min到max范围内的数值拆分为独立行:
SELECT id, [BETWEEN(min,max)] AS val FROM table A;
期望输出结果:
id val #### #### 1 1 1 2 1 3
以下提供除参考表关联外的几种通用解决方案,适配不同主流数据库:
1. MySQL(8.0+):递归CTE
利用递归公共表表达式(CTE)生成连续数值:
WITH RECURSIVE num_range AS ( SELECT id, min AS val, max FROM A UNION ALL SELECT id, val + 1, max FROM num_range WHERE val < max ) SELECT id, val FROM num_range ORDER BY id, val;
逻辑说明:先读取表中每行的初始min值作为起始行,然后递归自增数值,直到达到max为止,最终展开为连续行。
2. PostgreSQL:两种简便方式
方式一:递归CTE
和MySQL逻辑一致:
WITH RECURSIVE num_range AS ( SELECT id, min AS val, max FROM A UNION ALL SELECT id, val + 1, max FROM num_range WHERE val < max ) SELECT id, val FROM num_range ORDER BY id, val;
方式二:generate_series函数
PostgreSQL原生支持序列生成函数,代码更简洁:
SELECT A.id, generate_series(A.min, A.max) AS val FROM A ORDER BY A.id, val;
逻辑说明:generate_series直接生成min到max的连续数值序列,与原表关联后自动拆分为多行。
3. SQL Server:递归CTE
SQL Server 2005及以上支持递归CTE,注意递归次数限制:
WITH num_range AS ( SELECT id, min AS val, max FROM A UNION ALL SELECT id, val + 1, max FROM num_range WHERE val < max ) SELECT id, val FROM num_range ORDER BY id, val OPTION (MAXRECURSION 0); -- 若max-min差值超过100,需添加此参数解除默认递归次数限制
4. Oracle:递归CTE或层级查询
方式一:递归CTE(11gR2+)
WITH num_range(id, val, max_val) AS ( SELECT id, min, max FROM A UNION ALL SELECT id, val + 1, max_val FROM num_range WHERE val < max_val ) SELECT id, val FROM num_range ORDER BY id, val;
方式二:CONNECT BY层级查询
适合低版本Oracle:
SELECT A.id, A.min + LEVEL - 1 AS val FROM A CONNECT BY LEVEL <= A.max - A.min + 1 AND PRIOR A.id = A.id AND PRIOR SYS_GUID() IS NOT NULL;
逻辑说明:通过LEVEL层级值计算出min到max的每个数值,PRIOR SYS_GUID()用于避免同一id下的行产生重复关联。
内容的提问来源于stack exchange,提问作者stewe
相关产品推荐
相关产品推荐

