递归CTE中WHERE条件疑问:为何生成2011-01-01日期?
递归CTE中WHERE条件的作用机制及超出预期日期的原因
问题核心
你遇到的现象本质是:递归CTE的UNION ALL分支中,WHERE条件过滤的是「当前迭代的源行」,而非即将生成的新行。
具体逻辑拆解
你的原始查询执行流程如下:
- 初始行:
id=1, ymd='2010-01-01',直接加入结果集。 - 第一次递归:检查源行
ymd='2010-01-01'是否满足ymd < '2011-01-01',条件成立,生成新行ymd='2010-02-01'并加入结果集。 - 重复迭代,直到源行是
ymd='2010-12-01'时:'2010-12-01' < '2011-01-01'条件仍然成立,因此会基于该行生成新行ymd='2011-01-01'并加入结果集。
- 下一次迭代尝试用
ymd='2011-01-01'作为源行,此时'2011-01-01' < '2011-01-01'不成立,递归终止。
这就是为什么结果最后一行是2011-01-01——它是在源行2010-12-01满足条件时生成的,之后才终止递归。
修正方案
要让结果截止到2010-12-01,需要调整WHERE条件,确保只有当生成的新行符合预期范围时,才执行递归生成。有两种常用写法:
写法一:基于即将生成的日期判断
WITH RECURSIVE datesCte AS ( SELECT 1 id, date('2010-01-01') as ymd, 2010 year, 1 month, 1 quarter UNION ALL SELECT id+1, @d:=date_add(ymd,interval 1 month), year(@d), month(@d), quarter(@d) FROM datesCte WHERE date_add(ymd, interval 1 month) <= '2010-12-01' ) SELECT * FROM datesCte
写法二:基于当前源行的日期限制
WITH RECURSIVE datesCte AS ( SELECT 1 id, date('2010-01-01') as ymd, 2010 year, 1 month, 1 quarter UNION ALL SELECT id+1, @d:=date_add(ymd,interval 1 month), year(@d), month(@d), quarter(@d) FROM datesCte WHERE ymd < '2010-12-01' ) SELECT * FROM datesCte
两种写法都能确保最后生成的行是2010-12-01,且递归在生成该行后终止。
内容的提问来源于stack exchange,提问作者pgee70
相关产品推荐
相关产品推荐

