2011-08-16 89 views
3

下面的代碼將打印的所有日期貫穿本年度SQL Server上2008R2打印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,以下錯誤回報:

[錯誤] 42000 - [SQL服務器]終止聲明。在語句完成之前,遞歸363的最大值已經耗盡。

但是,處理器如何知道語句何時完成?

+1

「處理器」在**語句完成時不知道**,但它只知道「退出條件」('year(...)!= yr')沒有但它知道它需要繼續... –

+0

是啊...返回條件很隱含 – manuzhang

回答

4

你在這裏處理的是一個遞歸CTE。你應該只是read more關於它是如何工作的。

基本上,

  • 它獲得的第一行從錨部分(第一SELECT,UNION ALL的左側部分)設置。

  • 即行集變爲在第二SELECT(UNION ALL的右邊部分)別名爲x,稱爲遞歸部分

  • 遞歸部分產生基於x另一行組,這在下一迭代成爲新x。也就是,不是的初始組合行集合x和最後的結果集成爲新的x,但只有最後的結果集。

  • 上一步沒有對新x再次重複,循環繼續,直到這些是真實的:

    • 另一次迭代產生任何結果集;

    • 達到MAXRECURSION限制。

最終結果集由所有從遞歸CTE的兩個部分獲得的部分結果集。

應用上述您的特定查詢:

  • 第一個SELECT產生含今年1月1日ST(日)一行,併成爲第一x表。

  • 對於x第二SELECT的每一行產生含有如果它屬於同年相應下一個日期的行。因此,遞歸部分的第一次迭代有效地給了我們一月的2 。根據以上描述,結果集成爲新的x

  • 以下迭代結果在一月的3 RD,下一個產生的4個等。

  • 如果MAXRECURSION選項值已安全時,允許x包含十二月31 ST我們此刻到達,然後又重複,就會發現,第二天其實屬於不同的一年。這將導致產生一個空行集合,這反過來將導致遞歸CTE執行的終止。

+1

這是一個尾遞歸,不是嗎? – manuzhang

+0

是的,顯然。我不知道這種遞歸有自己的名字,所以不得不查找這個詞。感謝您的詢問。 :) –

+0

好吧,這裏的語法有點反直覺。我認爲值返回時會更新。但事實證明,值被更新和打印的路上,返回時什麼也沒有發生。許多thx的鏈接和詳細的答案。 – manuzhang

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) 
+0

thx ...當然有許多方法可以獲得當年的第一個日期......但是您認爲您的答案更快,遞歸參數更少?必須有一些原因,你在這裏更快地張貼 – manuzhang

+0

否,但它使用更少的資源。你爲每一行選擇年份,這並不是苛刻的。它也在削減一天中可能由於各種原因導致併發症的時間。 –

+0

「減少時間」...對不起,我不明白 – manuzhang

相關問題