Tsql 在SQL Server 2008R2上打印当前年份的所有日期

Tsql 在SQL Server 2008R2上打印当前年份的所有日期,tsql,sql-server-2008,Tsql,Sql Server 2008,以下代码将在SQL Server 2008R2上打印当前年份的所有日期 with x (dy, yr) as ( select dy, year (dy) yr from ( select getdate () - datepart (dy, getdate ()) + 1 dy -- the first date of the current year ) tmp1 union all select dateadd (dd, 1, dy), yr from x

以下代码将在SQL Server 2008R2上打印当前年份的所有日期

with x (dy, yr)
 as (
select dy, year (dy) yr
from (
     select getdate () - datepart (dy, getdate ()) + 1 dy
     -- the first date of the current year
     ) tmp1
union all
select dateadd (dd, 1, dy), yr
from x
where year (dateadd (dd, 1, dy)) = yr
 )
select x.dy
from x
option (maxrecursion 400)     
但有几点我无法理解

  • 据我所知,第一个日期应该打印400次,所有的重复都被过滤掉了吗
  • 当我将400更改为小于364时,返回以下错误:
  • [Err]42000-[SQL Server]语句终止。最大值 递归363在语句完成之前已耗尽


    但是,处理器如何知道语句何时完成

    这里要处理的是一个递归CTE。你应该知道它是如何工作的

    基本上

    • 它从定位部分(第一个选择,UNION ALL的左侧部分)获取第一行集

    • 该行集在第二次选择(UNION ALL的右侧部分)中的别名为
      x
      ,称为递归部分

    • 递归部分基于
      x
      生成另一行集,该行集在下一次迭代中成为新的
      x
      。也就是说,初始
      x
      和最后一个结果集的组合行集将成为新的
      x
      ,但仅是最后一个结果集

    • 针对新的
      x
      ,再次重复上一步,循环继续,直到其中一个为真:

      • 另一次迭代不产生结果集

      • 已达到最大递归限制

    最终结果集由从递归CTE的两个部分获得的所有部分结果集组成

    将上述内容应用于您的特定查询:

    • 第一个SELECT生成一行,其中包含今年的1月1日(日期),这将成为第一个
      x

    • 对于
      x
      的每一行,如果属于同一年,则第二次选择将生成一行,其中包含相应的下一个日期。因此,递归部分的第一次迭代有效地给出了1月2日。根据上述描述,结果集成为新的
      x

    • 下面的迭代结果是1月3日,下一次迭代产生第4次,以此类推

    • 如果MAXRECURSION选项值安全地允许我们到达
      x
      包含12月31日的时刻,那么另一次迭代将显示第二天实际上属于不同的一年。这将导致生成一个空行集,这反过来将导致递归CTE的执行终止


      • 这不是答案,这只是编写sql的另一种方式。安德烈M给了你一个冷静的回答,你应该相信他回答正确

        ;with x (dy) 
         as ( 
        select dateadd(year, datediff(year, 0, getdate()), 0) dy 
        union all 
        select dy + 1 
        from x 
        where year (dy) = year(dy+1) 
        ) 
        select x.dy 
        from x 
        option (maxrecursion 400) 
        

        “处理器”不知道语句何时完成,但它只知道“退出条件”(
        year(…)!=yr
        )尚未满足,因此它知道需要继续…是的。。。返回条件是隐式的,这是一个尾部递归,不是吗?是的,很明显。我不知道这种递归有它自己的名字,所以我必须查找术语。谢谢你的提问。:)这里的语法有点违反直觉。我认为返回时会更新这些值。但事实证明,这些值是在途中更新和打印的,返回时什么也不会发生。许多thx的链接和详细的答案。它似乎绝对违反直觉,我也第一次试图理解它。部分原因可能是因为他们必须使其尽可能类似于基于集合的操作。无论如何,一旦我意识到在CTE中,它的别名总是只指返回的最后一个(部分)结果集,一切都会很快到位。thx…当然有很多方法可以获得今年的第一个日期…但是你认为你的答案更快,递归参数更少吗?你把它贴在这里肯定是有原因的,不,但是它使用的资源更少。您正在为每一行选择年份,这是不必要的。它还减少了一天中的时间,这可能会由于各种原因导致并发症。“减少时间”…对不起,我不明白