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

时间:2011-08-16 04:59:22

标签: 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
where year (dateadd (dd, 1, dy)) = yr
 )
select x.dy
from x
option (maxrecursion 400)     

但有一点我无法理解

  1. 据我所见,第一个日期应该打印400次,是否过滤掉所有重复日期?
  2. 当我将400更改为小于364时,将返回以下错误:
  3.   

    [Err] 42000 - [SQL Server]语句终止。最大值   在语句完成之前,递归363已经用尽。

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

2 个答案:

答案 0 :(得分:4)

您在这里处理的是递归CTE 。你应该read more关于它是如何工作的。

基本上,

  • 它从锚点(第一个SELECT,UNION ALL的左侧部分)获取第一行集。

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

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

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

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

    • 达到MAXRECURSION限制。

最终结果集包含从递归CTE的两个部分获得的所有部分结果集。

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

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

  • 对于x的每一行,第二个SELECT会生成一个包含相应下一个日期的行如果它属于同一年。因此,递归部分的第一次迭代有效地为我们提供了1月份的2 nd 。根据以上描述,结果集变为新的x

  • 以下迭代产生1月份的3 rd ,下一次产生4 th ,依此类推。

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

答案 1 :(得分:1)

这不是答案,这只是编写sql的另一种方式。 Andriy 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)