如何在T-SQL中编写包含两个初始值的递归CTE?
处理SQL递归CTE中的多初始条件问题
嘿,这个问题我之前也踩过坑!当递归CTE需要多个初始行时,核心是把所有初始条件都放在锚点查询(也就是UNION ALL之前的部分)里,然后递归部分只需要基于已生成的行来推导后续项就行。针对你这个数列的例子,我来一步步拆解解决方案:
思路分析
你的数列定义是:a₁=2,a₂=3,aₙ=a(n-1)*a(n-2)。因为每一项依赖前两项的乘积,最高效的方式是在递归CTE里同时跟踪当前项和前一项的值,这样每次递归只需要用这两个值计算下一项,避免重复查询前序数据。
完整代码示例
WITH recur AS ( -- 锚点查询:包含两个初始条件 SELECT 1 AS n, 2 AS results, CAST(NULL AS BIGINT) AS prev_result -- n=1没有前一项,设为NULL UNION ALL SELECT 2 AS n, 3 AS results, 2 AS prev_result -- n=2的前一项是a₁=2 UNION ALL -- 递归部分:生成后续项 SELECT n + 1, results * prev_result, -- 计算当前项 = 当前值 * 前一项值 results -- 更新前一项为当前值,供下一次递归使用 FROM recur WHERE n >= 2 -- 只有n>=2时才有有效的前一项,才可以递归 AND n < 10 -- 终止条件:这里生成到n=10,你可以按需调整 ) -- 最终查询:只取n和对应的数列值,按n排序 SELECT n, results FROM recur ORDER BY n;
代码解释
- 锚点部分:用
UNION ALL把n=1和n=2的初始行合并,同时为n=2的行记录前一项的值,方便递归计算。 - 递归部分:
n + 1:生成下一个数列的序号results * prev_result:用当前项和前一项的乘积得到下一项的值results:把当前项的值赋值给prev_result,作为下一次递归的前一项
- 终止条件:
n < 10控制递归的结束,你可以根据需要修改这个数值(比如生成到n=20)。 - 数据类型注意:因为数列的乘积会快速增长,我用了
BIGINT类型来避免整数溢出,如果需要更大的数值,你可以换成DECIMAL或者对应数据库支持的大整数类型。
运行结果
执行上面的代码后,你会得到如下结果:
| n | results |
|---|---|
| 1 | 2 |
| 2 | 3 |
| 3 | 6 |
| 4 | 18 |
| 5 | 108 |
| 6 | 1944 |
| 7 | 209952 |
| 8 | 41428992 |
| 9 | 8681283072 |
| 10 | 35976347988992 |
对你原始代码的修正
你之前的写法把两个初始条件和递归部分都用UNION ALL连起来了,其实应该把初始条件作为锚点(前两个SELECT),然后递归部分是第三个SELECT,并且递归部分必须基于recur表来获取前序数据,不能凭空生成。上面的代码就是修正后的完整版本。
内容的提问来源于stack exchange,提问作者Przemek Kaczmarek




