2011-11-16 58 views
2

希望這將是一個容易回答的問題。SQL Server 2008中的月迄今

我正在處理需要MTD數據的表格。我們的一個SQL傢伙告訴我使用

MONTH (@monthtodate)= 11 

@monthtodate設置爲GetDate()在SQL Server Management Studio中的參數列表。因此,在「理論」中,他應該選擇月份(11),然後在今天獲得並在這兩個日期之間返回所有請求的數據。但我認爲這是不正確的。

在查看我的數據時,我開始認爲它只是返回11月整個月的數據,而不僅僅是MTD。我想,從技術上講,任何有0的東西都不會被計算出來。但是,這意味着它的代碼編寫不正確?

在你的意見,這會是更好的方式來回報MTD數據:事先大家

production_date <= @today and Production_Date >= DATEADD(mm, DATEDIFF(mm, 0, @today), 0) 

謝謝!

回答

2

以下是我的工作方式。這應該適用於任何版本的SQL Server。

需要注意的一件重要事情:首先,應該始終建立一個代表'現在'的單一值,即當前時刻。如果您現在在查詢中沒有一致的值,那麼當您的查詢執行時,您最終會得到一點信息,以便它在飛行中跨越日期邊界。沒有人願意爲他們上個月已經支付的東西記賬。最糟的是,邊緣的情況下盲蝽象是很難趕上,無論是開發商還是由QA,因爲無論是可能的工作,比方說,在11:59於12月31日

代碼:

declare 
    @dtNow datetime , 
    @Today datetime , 
    @dtFrom datetime , 
    @dtThru datetime 

--------------------------------------------------------------------------------------- 
-- set our effective notion of 'now'-ness. 
-- 
-- We need have a consistent notion of now, lest we get bit in the a$$ 
-- by an edge case where we cross a day/month/year boundary in mid-execution. 
-- 
-- NOTE: Mostly, we're interested in the *DATE* rather than the actual moment-in-time. 
--  So, we carry around two flavors here. 
--------------------------------------------------------------------------------------- 
set @dtNow = current_timestamp 
set @Today = convert(datetime,convert(varchar,@dtNow,112),112) 

--------------------------------------------------------------------------------------- 
-- compute the current date. 
-- 
-- 1. get the current date sans timestamp (effectively start-of-day) 
-- 2. add 1 day, then back off 3 millseconds to set it to the last tick of the current day 
-- 
-- NOTE: Depending on the requirements of your particular application (and the nature 
--  of your data), you might want to use the actual current date/time value as 
--  your upper bound. 
-- 
-- FURTHER NOTE: How far to back off is dependent on your date/time type: 
-- 
-- * For DateTime, the resolution is milliseconds and the last tick of the day 
-- is 997 milliseconds, so you need to back off 3ms from the start of the 
-- next day. 
-- 
-- * SmallDateTime has a 1 second resolution. The last tick of the day, natch, 
-- is 59 seconds, so you need to back off 1 second from the start of the next day. 
-- 
-- * For DateTime2, the user declares the precision in decimal fractions of a second, 
-- though its resolution is 100ns ticks. You'll need (especially if you're working 
-- with DateTime2 columns/variables of differing precision) experiment to figure out 
-- what traps Microsoft has set for you inside DateTime2 and what you need to do to 
-- make things work properly. 
-- 
--------------------------------------------------------------------------------------- 
set @dtThru = dateadd(ms,-3,dateadd(day,1,@Today)) 
--set @dtThru = @dtNow -- if you need the actual current date/time value 

--------------------------------------------------------------------------------------- 
-- compute start of month 
-- 
-- We do this by subtracting the day number of 'today' from the date/time value @today. 
-- That gives us the last day of the prior month. Then we add one day to get the first 
-- day of the current month. 
--------------------------------------------------------------------------------------- 
set @dtFrom = dateadd(day,1-day(@Today),@Today) 

--------------------------------------------------------------------------------------- 
-- finally, make your query for 'current month to date' 
--------------------------------------------------------------------------------------- 
select * 
from dbo.foobar t 
where t.recorded_date between @dtFrom and @dtThru 
+0

謝謝尼古拉斯!我知道這看起來很奇怪,但由於我對基本SQL有一點基本的瞭解,所以時間/日期很痛苦!這是我找到的最佳MTD答案! +1給你!我肯定會在我的數據庫課堂上分享這些內容。 –

+0

在兩者之間要小心,最好做 SQLMenace

+0

@SQLMenace:'x between y和z'與'x> = y和x <= z'完全相同。無論數據類型如何,都沒有區別。你還會注意到我在這裏使用的是DateTime而不是DateTime2:如果我使用的是Datetime2,我會將上限調整到適當的100ns的界限。 ''之間''使得代碼更乾淨,更易讀。但謝謝你的建議。 –

0

如果你問這些2個查詢是從性能的角度更好:

DECLARE @now datetime = GETDATE() 

SELECT * 
FROM yourTable 
WHERE Production_Date >= DATEADD(mm, DATEDIFF(mm, 0, @now), 0) 
AND Production_Date < @now 

SELECT * 
FROM yourTable 
WHERE YEAR(Production_Date) = YEAR(@now) 
AND MONTH(Production_Date) = MONTH(@now) 
AND Production_Date < @now 

然後第一個是,因爲它會使用在Production_Date索引(如果有)。但是,他們都應該返回相同的結果。