mysql 8.0+ 使用 with recursive 生成连续数字需包含锚点和递归成员,如 with recursive seq(n) as (select 1 union all select n+1 from seq where n

MySQL 8.0+ 怎么用 WITH RECURSIVE 生成连续数字
只有 MySQL 8.0 及以上版本才支持递归 CTE,低版本(如 5.7)直接报错 ERROR 1064。递归必须包含两个部分:锚点(anchor)和递归成员(recursive member),且递归查询不能有聚合、GROUP BY、ORDER BY(除非在最外层)等限制。
基本结构如下:
WITH RECURSIVE seq(n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM seq WHERE n <p>这会生成 1 到 100 的整数。注意:<code>n</code> 必须有明确的终止条件(<code>WHERE n ),否则会无限递归直到达到 <code>cte_max_recursion_depth</code> 限制(默认 1000),然后报错 <code>ERROR 3636</code>。</code></p><h3>为什么 <code>SELECT n FROM seq</code> 有时返回空或不完整</h3><p>常见原因是递归深度不够或初始值/终止条件逻辑反了。比如想生成 10–20,写成 <code>SELECT 10 UNION ALL SELECT n+1 FROM seq WHERE n > 20</code> 就永远进不了递归分支——因为初始 <code>n=10</code> 不满足 <code>n > 20</code>,结果只返回一行 10。</p>
- 终止条件必须让递归能“走起来”,且最终为假:用
或 <code> 配合递增,或 <code>>=/>配合递减 - 检查当前会话的递归上限:
SELECT @@cte_max_recursion_depth;,需要时可临时调高:SET SESSION cte_max_recursion_depth = 5000; - 如果生成大范围(如 1–100000),CTE 会构建完整中间结果集,内存和速度不如临时表或数字辅助表
生成带偏移、步长或字符前缀的序列怎么写
CTE 的递归列可以参与任意标量计算,不只是 n + 1。但所有计算必须是确定性的,不能引用外部表或使用随机函数。
例如生成偶数 2, 4, 6…20:
WITH RECURSIVE seq(n) AS ( SELECT 2 UNION ALL SELECT n + 2 FROM seq WHERE n <p>生成带前缀的编号(如 'ID-001', 'ID-002'):</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill2334" title="MySQL"><img src="https://img.php.cn/upload/skill/000/000/081/178900927846657.jpg" alt="MySQL" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill2334" title="MySQL" class="overflowclass">MySQL</a> <p class="overflowclass">编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。</p> </div> <a rel="nofollow" href="/xiazai/skill2334" title="MySQL" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div><pre class="brush:php;toolbar:false;">WITH RECURSIVE seq(n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM seq WHERE n <p>注意:<code>LPAD</code> 和 <code>CONCAT</code> 是安全的,但别在递归分支里用 <code>NOW()</code>、<code>RAND()</code> 或子查询,MySQL 会拒绝执行。</p><h3>替代方案:没有 CTE 时怎么凑出数字序列</h3><p>MySQL 5.7 或更老版本无法用 <code>WITH RECURSIVE</code>,常见绕过方式是利用系统表(如 <code>information_schema.columns</code>)做笛卡尔积“榨取”行数,但不可靠——表数量可能不足,且依赖元数据权限。</p><p>更稳妥的做法是建一个最小化数字表:</p><pre class="brush:php;toolbar:false;">CREATE TABLE nums (n INT PRIMARY KEY); INSERT INTO nums VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
再通过交叉连接生成更大范围:
SELECT a.n * 10 + b.n + 1 AS num FROM nums a CROSS JOIN nums b WHERE a.n * 10 + b.n + 1 <p>这种方案性能稳定、兼容性好,但需要提前建表;而 CTE 方案零依赖,适合一次性、中小规模(</p><p>真正要注意的是:别在应用层循环拼 SQL 插入数字,也别用存储过程 while 循环——这两者在大数据量下慢且难维护。CTE 或预置数字表,才是干净解法。</p>










