2014-10-07 181 views
15

我無法確定僅基於月和年來比較SQL中日期的最佳方法。僅基於月份和年份的SQL Server日期比較

我們根據日期進行計算,並且由於計費按月進行,因此月份的日期造成了更多的阻礙。

例如

DECLARE @date1 DATETIME = CAST('6/15/2014' AS DATETIME), 
     @date2 DATETIME = CAST('6/14/2014' AS DATETIME) 

SELECT * FROM tableName WHERE @date1 <= @date2 

因爲@ DATE1比@ DATE2大於以上例子將不返回任何行。所以我想找一種方法來消除這個問題。

同樣,出於同樣的原因,下面的情況讓我感到悲傷。

DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME), 
     @date2 DATETIME = CAST('6/15/2014' AS DATETIME), 
     @date3 DATETIME = CAST('7/1/2014' AS DATETIME) 

SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3 

我已經完成了日期的內聯轉換,以獲得指定日期的月份的第一天和最後一天。

SELECT * 
FROM tableName 
WHERE date2 BETWEEN 
    DATEADD(month, DATEDIFF(month, 0, date1), 0) -- The first day of the month for date1 
    AND 
    DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, date2) + 1, 0)) -- The lastday of the month for date3 

必須有一個更簡單的方法來做到這一點。有什麼建議麼?

+1

的SQL Server版本? – christiandev 2014-10-07 15:39:16

+0

@christiandev我們正在使用SQL 2008. – 2014-10-07 15:41:31

+1

另外,如果您不使用時間部分,則可以使用'DATE'數據類型。 – christiandev 2014-10-07 15:45:56

回答

15

爲了處理不等式,比如之間,我喜歡將日期/時間轉換爲YYYYMM表示形式,無論是字符串還是整數。在這個例子中:

DECLARE @date1 DATETIME = CAST('6/14/2014' AS DATETIME), 
     @date2 DATETIME = CAST('6/15/2014' AS DATETIME), 
     @date3 DATETIME = CAST('7/1/2014' AS DATETIME); 

SELECT * FROM tableName WHERE @date2 BETWEEN @date1 AND @date3; 

我會寫查詢爲:

SELECT * 
FROM tableName 
WHERE year(@date2) * 100 + month(@date2) BETWEEN year(@date1) * 100 + month(@date1) AND 
               year(@date3) * 100 + month(@date1); 
6

您可以加入這些日期的MONTHYEAR值:

SELECT * 
FROM tableName 
WHERE YEAR(@date1) = YEAR(@date2) AND MONTH(@date1) = MONTH(@date2) 
+2

+1你打我幾秒:-) – Tanner 2014-10-07 15:41:21

+0

謝謝你的迴應,但這並沒有解決日期範圍。例如'WHERE date1 BETWEEN date2 AND date3' – 2014-10-07 15:43:08

+1

@AndyEvans回滾我的編輯,對範圍的第二個想法更好地使用GordonLinoff的答案。 – DavidG 2014-10-07 15:49:48

13

你可以在給定日期的月份和年份過濾到當前日期,像這樣:

SELECT * 
FROM tableName 
WHERE month(date2) = month(getdate()) and year(date2) = year(getdate()) 

只需更換用你想要的日期的GETDATE()方法。

+1

儘管你仍然值得+1 :) – DavidG 2014-10-07 15:42:03

+0

感謝您的回覆,但是這並沒有解決日期範圍問題。例如'WHERE date1 BETWEEN date2 AND date3' – 2014-10-07 15:42:39

+1

@AndyEvans所以你想要所有記錄的日期在一年的一個月內? – Tanner 2014-10-07 15:44:53

8

首先,我會使用一個格式是明確的日期,像標準'YYYYMMDD',而不是'6/15/2014'你有一直在使用。阿龍貝特朗的博客解釋遠遠比我更好,各個方面,這可能會出錯:
Bad habits to kick : mis-handling date/range queries

對於具體問題,你該發現的第一個和個月的最後幾天(爲date1的最後一個查詢和date3),在我看來是正確的。你只需要雖然月的第一天(DATE1下個月的DATE3的第一天的第一天),如果你避免邪惡BETWEENWhat do BETWEEN and the devil have in common?

SELECT * 
FROM tableName 
WHERE date2 >= DATEADD(month, DATEDIFF(month, '19000101', @date1), '19000101') 
    AND date2 < DATEADD(month, 1+DATEDIFF(month, '19000101', @date3), '19000101') ; 

的查詢工作,因爲它是,不管數據類型爲date2DATE,DATETIME,DATETIME2SMALLDATTEIME)。

加分點,date2上的索引將被優化器這樣考慮。


改進,根據(但不同)阿龍的博客文章,與DATEDIFF()計算表達式時避免與基數估計的問題:
Performance Surprises and Assumptions : DATEDIFF

SELECT * 
FROM tableName 
WHERE date2 >= CONVERT(DATE, DATEADD(day, 1 - DAY(@date1), @date1)) 
    AND date2 < DATEADD(month, 1, 
         CONVERT(DATE, DATEADD(day, 1 - DAY(@date3), @date3))) ;