2017-09-26 176 views
0

如果用戶選擇範圍,如:檢查日期落在月份和年份範圍內

  • 開始:2016年11月
  • 結束9月2017年,

我想包括所有結果在2016-11-01至2017-09-30的範圍內。

我試着將年,月和日連在一起,但問題是不是所有的月份都有相同的最後一天。雖然我知道所有月份從第01天開始,但一個月的結束日期可以是28,29,30或31.

有沒有辦法在不構建日期的情況下執行此操作? SqlServer 2008沒有EOMONTH函數,我覺得比任何更復雜的東西都不是正確的解決方案。我想避免這種情況:

WHERE 
    DateCol >= '2016' + '-' + '11' + '-01' AND 
    DateCol <= '2017' + '-' + '09' + '-30' 
+3

'其中DATE_1> = '20161101' 和DATE_1 <=「20170930'' - 唯一真正安全的格式在SQL Server中的日期/時間文字,至少對於'datetime'和'smalldatetime',是:'YYYYMMDD'和'YYYY-MM-DDThh:mm:ss [.nnn]' - [踢壞的習慣:錯誤處理日期/範圍查詢 - Aaron Bertrand](http ://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick-mishandling-date-range-queries.aspx) – SqlZim

+2

https://blogs.msdn.microsoft.com/ samlester/2013/09/23/emonth-equivalent-in-sql-server-2008-r2-and-below/ – ttugates

+0

@SqlZim,我沒有真正問過格式。年份和月份由用戶選擇。因此,如果他們選擇了2017年9月,您怎麼知道在「20170930」日期附加30? – user7733611

回答

1

在我看來,最簡單和最好的答案是從開始的月份的第一個月到結束月份之後的月份的第一個月,並使第二個比較不包含在內。

換句話說,而不是這樣的:

WHERE 
    DateCol >= '2016' + '-' + '11' + '-01' AND 
    DateCol <= '2017' + '-' + '09' + '-30' 

簡單:

WHERE 
    DateCol >= '2016' + '-' + '11' + '-01' AND 
    DateCol < '2017' + '-' + '10' + '-01' 
+0

這似乎是一個好主意。但我不確定在12月的情況下我會做什麼。這意味着我必須有條件地增加年份(並將月份從12更改爲1)。 – user7733611

+0

使用'DATEADD(月,...)'功能很容易。 –

+0

@Sami,爲什麼不呢? –

0

在2008年,你可以簡單地轉換成字符串

Select Date1=convert(date,'November 2016') 
     ,Date2=dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017'))) 

返回

Date1  Date2 
2016-11-01 2017-09-30 

所以WHERE將是很重要的興這樣

... 
Where DateCol between convert(date,'November 2016') 
        and dateadd(DAY,-1,dateadd(MONTH,1,convert(date,'September 2017'))) 
+0

我認爲OP的問題是幾個月,30或31或28的結束。 – Sami

0

你可以使用下面的SELECT語句傳遞一個字段或日期也得到任何一個月(及任何一年)的最後日期:

DECLARE @dtDate DATE 
SET @dtDate = '09/25/2016' 
SELECT CAST(DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@dtDate)+1,0)) AS DATE) AS LastDay_AnyMonth 

請提供一些示例數據和期望的結果,我會進一步更新我的答案。

+0

在尋找EOMONTH的替代方案時,我確實考慮了這一點。我最終想避免甚至必須弄清楚這個月的最後一天。 – user7733611

+0

你試圖避免搞清楚這個月的最後一天是什麼原因? – NonProgrammer

+0

我可以弄明白。但從邏輯上講,它是不相干的,對嗎?而是專注於比較幾個月和幾年。 – user7733611

0

在這裏你去:

DECLARE @YourTable TABLE (YourData DATE); 


INSERT INTO @YourTable VALUES 
('2016-11-01'), 
('2016-09-05'), 
('2017-03-03'), 
('2017-11-11'), 
('2017-12-14'), 
('2017-09-30'); 

WITH CTE AS (
    SELECT YourData 
    FROM @YourTable 
    WHERE YEAR(YourData) =2016 AND MONTH (YourData) >= 11 
    ) 
    SELECT YourData 
    FROM @YourTable 
    WHERE YEAR(YourData) =2017 AND MONTH (YourData) <= 9 
    UNION ALL 
    SELECT YourData 
    FROM CTE; 

沒有必要知道這個月(28或30或31)結束。

+0

這是行不通的。您排除2016年的數據。 – NonProgrammer

+0

你的答案仍然排除如2017-01-01 – user7733611

+0

@ user7733611的結果查看更新。 – Sami

1

有一種更快的方式做到這一點:

DECLARE @minDate DATE 
DECLARE @maxDate DATE 
SET @minDate = XXXXX 
SET @maxDate = YYYYY 

-- Get the first day of the month minDate. 
SET @minDate = CONVERT(datetime,CONVERT(varchar(6),@minDate,112)+'01',112) 
-- Get the last day of the month minDate. 
SET @maxDate = CONVERT(datetime,CONVERT(varchar(6),@maxDate,112)+'01',112) 
SET @maxDate = DATEADD(day, -1, DATEADD(month, 1, @maxDate)) 


SELECT * FROM myTABLE WHERE DateCol >= @minDate AND DateCol <= @maxDate 

或者:

SELECT * FROM myTABLE 
WHERE DateCol >= CONVERT(datetime,CONVERT(varchar(6),XXXXX,112)+'01',112) 
    AND DateCol <= DATEADD(day, -1, DATEADD(month, 1, CONVERT(datetime,CONVERT(varchar(6),YYYYY,112)+'01',112))) 

對於XXXXX和YYYYY而不是「2017-09-30」,使用類似CONVERT(datetime,'20170930',112)或CONVERT(datetime,'09 -30-2017',110)的語法,但使用SQL Server隱式從char到datetime轉換(依靠服務器配置:可能有危險!!!))。

使用此語法更快,因爲@minDate和@maxDate不需要任何評估。這樣的索引,可以直接使用...

否則的標量函數將模擬EOMONTH()的行爲可能是有用的...

+0

你介意解釋這一行:CONVERT(datetime,CONVERT(varchar(6),XXXXX,112)+'01',112)112是什麼? – user7733611

+1

112表示CONVERT期望第二個參數爲日期的ISO文本格式:YYYYMMDD。 110適用於美國格式:MM-DD-YYYY。有關詳細信息,請參見https://www.w3schools.com/sql/func_sqlserver_convert.asp ... – clementakis

+1

可以通過'SELECT CAST(getdate()AS VACHAR(20))'來檢查日期到char的隱式轉換格式。結果爲您提供了SQL Server期望的文本格式。這可以從一臺機器到另一臺機器,即使在同一個compagny ... – clementakis

0

執行基於日期的操作的有用的結構是利用日期維度表。您正在創建一個查詢表,該表包含大量關於日期的大量信息。然後,您可以根據您擁有的信息查詢表格。該表格足夠小,因此不會引起重大的性能問題。

在你的具體情況下,你有月份和年份。您可以將其插入日期維度表中,以獲取從開始月份開始的月份的第一個月份和結束月份的月份的最後一個月份。您現在有一個時間範圍可以在沒有任何複雜邏輯或運算的情況下進行搜索。

阿龍貝特朗解釋了它在這裏深入:https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/

相關問題