【问题标题】:Incorrect date comparison results in SQL Server 2008 R2SQL Server 2008 R2 中的日期比较结果不正确
【发布时间】:2012-03-01 21:06:20
【问题描述】:

我有一个 LINQ 2 SQL 查询,它为我提供了 2012 年 2 月的结果列表。结果 where 子句是

DECLARE @p0 DateTime = '2012-02-01 00:00:00.000'
DECLARE @p1 DateTime = '2012-02-29 23:59:59.999'
....
WHERE (CONVERT(DATE, [t0].[DatePlaced]) >= @p0) AND (CONVERT(DATE, [t0].[DatePlaced]) <= @p1)

运行时,我会显示 2012 年 3 月 1 日的结果以及 2012 年 2 月的所有结果。

如果我将 where 子句更改为使用 BETWEEN,则结果仅包含 2 月的日期。

WHERE [t0].[DatePlaced] BETWEEN @p0 AND @p1

我正在使用 .net 4 和 SQL Server 2008 R2,有和没有 SP1。

将日期切换为 2011 年 3 月 1 日并将我的查询的结束日期切换为 '2011-02-28 23:59:59.999' 产生了相同的结果。

除了使用 LINQ 2 SQL 不支持的 BETWEEN 之外,还有其他方法可以获得 2/2012 的结果吗?

【问题讨论】:

    标签: linq-to-sql datetime sql-server-2008-r2


    【解决方案1】:

    .999 舍入到第二天的午夜。你可以检查一下:

    DECLARE @p1 DateTime = '2012-02-29 23:59:59.999';
    SELECT @p1;
    

    你得到了什么?

    与其试图找出今天的最后一刻(这将根据数据类型和精度而有所不同),而是您想要的是一个开放式日期范围:

    DECLARE @p0 DATE = '2012-02-01',
            @p1 DATE = '2012-03-01';
    ....
    WHERE [t0].[DatePlaced] >= @p0
    AND [t0].[DatePlaced] < @p1
    

    更简单的方法是输入开始日期并说:

    DECLARE @p0 DATE = '2012-02-01';
    
    ....
    WHERE [t0].DatePlaced >= @p0
    AND [t0].DatePlaced < DATEADD(MONTH, 1, @p0)
    

    有关日期时间最佳实践的一些详细想法:

    关于为什么BETWEEN(以及扩展名&gt;= AND &lt;=)是邪恶的一些信息:

    【讨论】:

      【解决方案2】:

      如果您需要经常按月选择,您可以考虑在表中添加两个计算列 - 一个用于月份,一个用于年份:

      ALTER TABLE dbo.YourTable
      ADD DatePlacedYear AS YEAR(DatePlaced) PERSISTED
      
      ALTER TABLE dbo.YourTable
      ADD DatePlacedMonth AS MONTH(DatePlaced) PERSISTED
      

      这两个新列是由 SQL Server 自动计算的,它们是持久化的(例如,表存储的一部分),如果这对你有意义的话,你甚至可以在它们上面放置一个索引。

      有了这些,您现在可以使用如下查询:

      SELECT (columns)
      FROM dbo.YourTable
      WHERE DatePlacedYear = 2012 AND DatePlacedMonth = 2
      

      获取 2012 年 2 月以来的所有数据。

      这是一个经典的空间与速度权衡 - 通过为每行存储两个额外的列,您需要更多空间 - 但作为回报,查询变得更容易,如果您在 (DatePlacedYear, DatePlacedMonth) 上有索引,您的查询应该(理想情况下)相当快。

      【讨论】:

      • 我没有添加计算列,而是简单地与日期的月份和年份部分进行比较。我敢肯定有一个性能折衷,但它只用于内部报告,所以现在这不是什么大问题。
      【解决方案3】:

      不要使用AddMilliseconds(-1) 尝试使用AddMilliseconds(-3)

      查看this question SQL Server 如何处理毫秒数

      【讨论】:

      • 依赖毫秒是有问题的。如果基础数据类型转换为 SMALLDATETIME 会怎样?现在你的结果再次四舍五入。如果转换为 DATETIME2(>2) 会怎样?现在你的范围结束实际上是在一天结束之前,理论上你可能会错过数据。开放式日期范围确实是获取一整天数据的唯一面向未来的方法。
      猜你喜欢
      • 2012-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-01
      • 1970-01-01
      • 2011-07-09
      • 1970-01-01
      相关资源
      最近更新 更多