2013-06-27 97 views
-4

我想問3個關於下面的代碼的問題(請原諒冗長的代碼清單,我希望這些代碼能夠提供足夠的上下文)。存儲過程中的SQL Server日期計算

請注意,這裏的代碼取決於它執行的日期。出於這個原因,我的問題涉及到一個假設的情況有兩種不同的執行日期:

  1. 2014年3月1日
  2. 2014年1月1日

我的問題是在我上的這一些地區的理解是否正確的,即:

A。該SELECT DATEADD表達式(第1行)將:

  • 2014年3月1日創建的日期時間2014-02-31 23:59:59

。上線碼6-9將:

  • 2014年3月1日創建日期時間2014-02-01 00:00:00
  • 2014年1月1日創建日期時間2013-02-01 00:00:00

C。上線11-14的代碼將:

  • 2014年3月1日創建日期時間2015-01-30 00:00:00
  • 2014年1月1日創建日期時間2014-01-30 00:00:00

這是理解是否正確?

1. SET @ldpmth = (SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))) 
2. SET @yr = (SELECT YEAR(@ldpmth)) 
3. SET @mth = 0 
4. SET @dy = 0 
5. 
6. SET @fysdate = (SELECT CASE WHEN MONTH(@ldpmth) >= 2 THEN 
7. DATEADD(MM, 1,CAST(CAST(@[email protected][email protected] AS NVARCHAR(50)) AS DATETIME)) 
8. ELSE DATEADD(MM, 1, CAST(CAST((@yr-1)[email protected][email protected] AS NVARCHAR(50)) 
9. AS DATETIME)) END) 
10. 
11. SET @fyedate = (SELECT CASE WHEN MONTH(@ldpmth) >= 2 THEN 
12. DATEADD(YY, 1, CAST(CAST(@[email protected][email protected] AS NVARCHAR(50)) AS DATETIME)) + 30 
13. ELSE DATEADD(YY, 1, CAST(CAST((@yr-1)[email protected][email protected] AS NVARCHAR(50)) 
14. AS DATETIME)) + 30 END) 

(謝謝所有誰迄今回答了。其實,這是在我工作的地方,幾年前開發的(但沒有記錄)代碼,我一直負責其轉換爲一個可行的形式客戶端使用Crystal Reports)

+1

爲什麼不能用'2014-03-01'代替'GETDATE()'並自己測試它們? – Kermit

+0

對於問題A,你做錯了。你可能試圖捕獲上個月發生的所有事情,並且你正在努力計算一個包容性的端點(目前排除了發生在那天的最後一分鐘x毫秒內的任何事情) - 計算起來要容易得多當你處理連續時,一個*獨佔*上限。 –

回答

2

自2014年3月1日創建日期時間2014年2月31日23:59:59

號AFAIK,沒有任何DBMS這是如此愚蠢,它認爲2月31日是一個交流兩個日期。第1行的SQL語句將返回值'Feb 28 2014 23:59:59'。

您可以將實際日期替換爲GETDATE()和猜測來測試您的所有語句。在第一個查詢,例如,使用

SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'2014-03-01'),0)); 
               ^^^^^^^^^^ 

你或許可以在本地運行一個版本的SQL Server。 SQL Server 2008甚至安裝在Windows XP上。如果你不能忍受,那麼總是有sqlfiddle.com。

+1

哈哈,你錯了。 MySQL有時是愚蠢的:) –

+1

@ypercube:恩,是的。和MS Access用於讓你乘以日曆日期。 (我不知道它是否仍然有效。)您可以將2013年1月12日的日期乘以2014年2月17日的日期,並獲得一些數字。我想,在方形日期中有一些數字。 –

+0

謝謝Mike Sherrill的回答,尤其是謝謝。對於在本地SQL服務器中測試這一點的提示(我已安裝了一個,但我在藍月亮中使用它一次,因爲SQL不是我常規工作任務的一部分)。 2月31日的日期是我的一個愚蠢的錯字(這就是我得到的衝動)。 – user100487

0

這可以在SQL Server Management Studio(SSMS)中輕鬆測試。我會回答第一個,你可以自己測試下兩個。

問:

A.該DATEADD(1號線)將在2014年3月1日創建日期時間2014年2月31日23:59:59

答:沒有,因爲二月不可能有31天,所以不能返回「2014-02-31`

證明:

select DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,'2014-03-01'),0)) 

Results 

(No column name) 
2014-02-28 23:59:59.000 
+0

感謝肯懷特的答案,也爲本地測試的提示。 – user100487

0

對於(B)和(C),如果您提出了您的問題,請改爲「我的財務年度從2月1日至30日(原文如此)1月份 - 我如何獲取當前財政年度的開始日期和結束日期,我會提出:

SET @fysdate = DATEADD(year,DATEDIFF(month,'19000201',GETDATE())/12,'19000201') 

和:

SET @fyedate = DATEADD(year,DATEDIFF(month,'19000201',GETDATE())/12,'19010131') 

(請注意,本次發現的1月31日,而不是30日。我認爲你原來的問題是粗心)。 (A),正如我所指出的那樣,我認爲你的問題再次表達不了 - 如果你試圖找到一個時期的終點,那個時期是在日期時間上定義的(而不是僅僅日期),所以可以非常容易構建一個獨家上限:

SET @ldpmth = DATEADD(month, DATEDIFF(month,0,GETDATE()),0) 

此結合(成與<比較,而不是<=BETWEEN使用)不人爲地排除與時間,例如任何值23:59:59.527。還要注意的是,如果財務年度結束日期計算將用於包含時間的日期時間值,我會再次建議計算上限的獨佔,並用19010201代替19010131

因此,總的來說,我並不認爲我已經回答了您提出的問題,但我想我已經提供了您應該尋求的答案。

+0

謝謝達米安。其實你的回答解釋了我對這段代碼的一些問題,儘管我不能使用它(因爲我需要寫一些我可以在Crystal Report設計器中使用的東西)。是的,我確實看到我原來的問題至少有兩個日期錯別字(1月30日和2月31日)。 – user100487