SQL Server日期比较仅基于月份和年份

时间:2014-10-07 15:33:38

标签: sql sql-server sql-server-2008 date

我无法确定仅根据月份和年份比较SQL日期的最佳方法。

我们根据日期进行计算,因为按月计费,每月的日期会造成更多障碍。

例如

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

必须有一种更简单的方法来做到这一点。有什么建议吗?

7 个答案:

答案 0 :(得分:20)

要处理不等式,例如之间,我喜欢将日期/时间转换为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);

答案 1 :(得分:15)

您可以将指定日期的月份和年份过滤到当前日期,如下所示:

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

只需将GETDATE()方法替换为您想要的日期。

答案 2 :(得分:8)

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

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

答案 3 :(得分:8)

首先,我会使用明确的日期格式,例如标准'YYYYMMDD',而不是您一直使用的'6/15/2014'。 Aaron Bertrand的博客解释得比我更好,这可能是出错的各种方式:
 的 Bad habits to kick : mis-handling date / range queries

对于特定问题,我的最后查询找到了月份的第一天和最后几天(对于date1和date3),在我看来是正确的轨道。您只需要几个月的第一天(date1的第一天和date3的下个月的第一天),如果您避开 evil BETWEEN What 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') ;

无论date2DATEDATETIMEDATETIME2SMALLDATTEIME的数据类型如何,查询都按原样运行。

奖励点,优化器会以这种方式考虑date2上的索引。


改进,根据(但另一个)Aaron的博客文章,以避免在使用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))) ;

答案 4 :(得分:1)

这是一道经典的数学题。很容易将月份与月份进行比较。那就是将年份与一年中的月数相乘,然后将一年中的月份相加。这将给出一个可以在一个范围内进行比较的整数。

例如:2021 年 7 月将是 07+12*2021

答案 5 :(得分:0)

您可以使用类似“ yyyyMM”的格式设置日期格式,因此只会选择同一年的月份。

SELECT * 
FROM tableName 
WHERE FORMAT(date_month_bill, 'yyyyMM') < FORMAT(DATEADD(MONTH, -1, GETDATE()), 'yyyyMM') 
AND FORMAT(date_month_bill, 'yyyyMM') > FORMAT(DATEADD(MONTH, -3, GETDATE()), 'yyyyMM')

答案 6 :(得分:0)

我使用EOMONTH()将日期滚动到同一日期,并进行了比较。因此,如果我将date1作为09/18/2019和date2作为09/16/2019,它们都将累积到09/30/2019。这不是您问题的直接答案,但在我的情况下有效。