mysql 8.0+才支持with语法,低于8.0.1版本执行会报语法错误;递归cte必须显式使用with recursive,缺关键字或无终止条件均导致失败;推荐用于逻辑分层、树形结构等可读性与维护性优先的场景。

WITH在MySQL 8.0+才可用,低于这个版本会报错
MySQL直到8.0.1版本才原生支持WITH语法,如果你执行WITH t AS (SELECT 1) SELECT * FROM t却遇到ERROR 1064 (42000): You have an error in your SQL syntax,大概率是MySQL版本太低。用SELECT VERSION()确认一下,低于8.0.1就别硬试了——临时表或子查询是更稳妥的替代方案。
递归CTE必须显式声明RECURSIVE关键字
MySQL要求递归查询必须写WITH RECURSIVE,漏掉RECURSIVE会导致语法错误,不像PostgreSQL可以省略。比如生成1到5的数字序列:
WITH RECURSIVE nums(n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM nums WHERE n <p>注意三点:<code>nums</code>必须有列别名(<code>(n)</code>);递归部分不能用<code>ORDER BY</code>或<code>LIMIT</code>;默认最大递归深度是1000,超限会报<code>ERROR 3636 (HY000): Recursive query aborted after 1001 iterations</code>,可通过<code>SET SESSION cte_max_recursion_depth = 2000</code>临时调高。</p><h3>多个CTE之间用逗号分隔,不能用多个WITH</h3><p>想定义两个临时结果集,不能写两次<code>WITH</code>,而要用逗号连接。下面这种写法是错的:</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 a AS (SELECT 1) WITH b AS (SELECT 2) SELECT * FROM a, b;
正确写法是:
WITH a AS (SELECT 1), b AS (SELECT 2) SELECT * FROM a, b;
另外,CTE只在紧随其后的单条语句中有效,不能跨SELECT复用;如果后续还要用,得重复定义,或者改用视图/临时表。
CTE不是物化视图,性能未必比子查询好
很多人以为CTE“更清晰=更高效”,其实MySQL优化器对CTE的处理方式和子查询接近,甚至可能更慢——尤其当CTE被多次引用时,MySQL默认不缓存结果(除非加MATERIALIZED提示,但仅限8.0.23+)。例如:
WITH sales AS (SELECT * FROM orders WHERE status = 'paid') SELECT COUNT(*) FROM sales WHERE amount > 100 UNION ALL SELECT AVG(amount) FROM sales;
上面的sales会被执行两次。若数据量大,不如先建临时表,或确保WHERE条件能走索引。真正值得用CTE的场景是:逻辑分层明显(比如先清洗再聚合)、递归结构、或避免嵌套过深导致可读性崩坏。










