递归CTE使用UNION ALL为何未返回重复数据?
为什么递归SQL返回的日期没有重复?
哈哈,你这是对递归CTE的执行逻辑产生了一个非常典型的误解!我来给你掰扯清楚:
首先,先还原一下你大概率用到的那种递归日期SQL(毕竟这是生成连续日期的经典写法):
WITH DateCTE AS ( -- 锚点成员:初始日期 SELECT CAST('2011-09-01' AS DATE) AS dt UNION ALL -- 递归成员:基于上一次结果生成下一个日期 SELECT DATEADD(day, 1, dt) FROM DateCTE WHERE dt < CAST('2011-10-01' AS DATE) ) SELECT dt FROM DateCTE;
你之前的认知是:每次递归迭代都会把所有已生成的日期都加1,然后和之前的集合做UNION ALL,这样会出现大量重复——但这完全搞错了递归CTE的工作方式!
递归CTE的执行是严格分阶段的:
- 第一步:执行锚点成员:只运行一次,得到初始结果集(这里就是
2011-09-01这一行)。 - 第二步:递归迭代:每一次递归,只会针对上一轮递归输出的结果集进行计算,而不是整个历史所有行。
拿这个例子一步步看:
- 第一次递归:只处理锚点的
2011-09-01,加1天得到2011-09-02,和锚点结果UNION ALL后,集合是[2011-09-01, 2011-09-02]。 - 第二次递归:只处理上一轮返回的
2011-09-02,加1得到2011-09-03,UNION ALL后集合变成[2011-09-01, 2011-09-02, 2011-09-03]。 - 以此类推,每一轮只会新增一个全新的日期,直到递归成员生成的日期触达
2011-10-01,WHERE条件不满足,递归终止。
所以最终结果自然是从2011-09-01到2011-10-01的所有唯一日期,完全不会有重复。
如果真的要得到你预期的重复数据,那得换写法——比如每次都基于锚点成员来生成新行,但那已经不是递归CTE的常规用法啦。
内容的提问来源于stack exchange,提问作者Shawn Li
相关产品推荐
相关产品推荐

