2014-10-07 225 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))) ; 
相关问题