【问题标题】:How to compare datetime with only date in SQL Server如何在 SQL Server 中将日期时间与仅日期进行比较
【发布时间】:2014-08-29 08:29:50
【问题描述】:
Select * from [User] U
where  U.DateCreated = '2014-02-07'     

但在数据库中,用户是在2014-02-07 12:30:47.220 创建的,而我只输入'2014-02-07'

不显示任何数据

【问题讨论】:

    标签: sql sql-server tsql datetime


    【解决方案1】:

    如果您使用的是 SQL Server 2008 或更高版本,则可以使用日期数据类型:

    SELECT *
    FROM [User] U
    WHERE CAST(U.DateCreated as DATE) = '2014-02-07'
    

    应该注意,如果日期列被索引,那么这仍然会利用索引并且是 SARGable。这是日期和日期时间的特例。

    可以看到SQL Server其实把这个变成了>和

    我刚刚在一张大表上尝试过这个,根据@kobik 的 cmets 在日期列上有一个二级索引,并且索引仍然使用,对于使用 BETWEEN 或 >= 和

    SELECT *
    FROM [User] U
    WHERE CAST(U.DateCreated as DATE) = '2016-07-05'
    

    【讨论】:

    • 似乎我的目标是这个答案,但事实并非如此,因为我们几乎同时发布,我不知道你的答案。但是为了减少你再次增加图像大小的需要,我改变了我的“不做”示例,也许这会有所帮助?
    • 这些天AaronsBad 数据库进展如何?
    • @Pure.Krome 如您所知,这是一个不再存在的临时数据库。
    • “应该注意,如果日期列被索引,那么它仍然会利用索引并且是 SARGable” - 当 DateCreated 是 PK 或聚集索引时,这是正确的。对于非聚集索引,有一个全表扫描。
    • @kobik 事实上我刚刚做了一个测试,这个解决方案使用一个大表的索引。其他解决方案没有。
    【解决方案2】:

    不要试图做这样的事情:

    Select * from [User] U where convert(varchar(10),U.DateCreated, 120) = '2014-02-07'
    

    这是一个更好的方法:

    Select * from [User] U 
    where U.DateCreated >= '2014-02-07' and U.DateCreated < dateadd(day,1,'2014-02-07')
    

    见:What does the word “SARGable” really mean?

    编辑 + 避免在 where 子句(或连接条件)中对数据使用函数有两个根本原因。

    1. 在大多数情况下,对数据使用函数来过滤或连接会消除优化器访问该字段索引的能力,从而使查询变慢(或更“昂贵”)
    2. 另一个是,对于涉及的每一行数据,至少要执行一个计算。这可能会向查询中添加数百、数千或数百万次计算,以便我们可以与2014-02-07 等单一标准进行比较。改变标准以适应数据的效率要高得多。

    “修改标准以适应数据”是我描述“使用SARGABLE谓词”的方式


    并且不要在两者之间使用。

    日期和时间范围的最佳做法是避免 BETWEEN 和 始终使用以下形式:

    WHERE col >= '20120101' AND col

    http://sqlmag.com/t-sql/t-sql-best-practices-part-2 (Itzik Ben-Gan)

    【讨论】:

    • 如果你有时间应该解释为什么一个比另一个更好(索引使用),这将使它成为一个更好的答案
    • 说起来容易做起来难,有几种数据类型(日期、日期时间、日期时间2、小日期时间)以及不同的 mssql 版本需要考虑。恐怕一个答案并不适合所有。但我要加个注释。
    • 如果你使用 cast(datetime as date) 它仍然会使用 datetime 字段的索引。试试看。
    • @Steve Ford,我同意——在 mssql 的后期版本中——这就是我说“说起来容易做起来难”的原因;很难在所有条件下都正确。然而,即使优化器 can 有时会进行补偿,使用 sargable 谓词也是一种很好的做法。
    • 最安全的date literal 格式是'YYYYMMDD'。数据类型:date 或 datetime 或 time 或 datetime2 或 smalldatetime 都没有格式,因为它们都存储为数字。对于日期文字 'YYYY-MM-DD' 并不完全安全,有一个区域设置可能会将该序列误解为 YYYY-DD-MM
    【解决方案3】:

    当然,这是一个旧线程,但要使其完整。

    从 SQL 2008 开始,您可以使用 DATE 数据类型,因此您可以简单地执行以下操作:

    SELECT CONVERT(DATE,GETDATE())
    
    OR
    
    Select * from [User] U
    where  CONVERT(DATE,U.DateCreated) = '2014-02-07' 
    

    【讨论】:

      【解决方案4】:

      根据您的查询 Select * from [User] U where U.DateCreated = '2014-02-07'

      SQL Server 正在比较确切的日期和时间,即(比较 2014-02-07 12:30:47.2202014-02-07 00:00:00.000 是否相等)。这就是为什么比较的结果是错误的

      因此,在比较日期时,您还需要考虑时间。您可以使用
      Select * from [User] U where U.DateCreated BETWEEN '2014-02-07' AND '2014-02-08'

      【讨论】:

      • 不幸的是,SQL 定义了between,两端都等于(>= 和 select * from x where col_1 between 'A' and 'M' 包括 A 和 M(当然还有 B 到 L)。 between 的包容性对于文档索引之类的东西来说非常棒。但对于日期/时间范围,这是一场灾难,因为它会产生重叠。我知道使用 between 看起来很棒,但实际上 SQL between 在日期范围内无法正常工作。始终使用 >= 和 U.DateCreated >='2014-02-07' and U.DateCreated < '2014-02-08'
      • @Used_By_Already 同意你的观点,但对于这种特殊情况(有问题),between 是可以的。对于日期范围,您使用&gt;=&lt; 的建议无疑比between 更可取。我只想说,我们在比较日期时也应该考虑时间。
      【解决方案5】:

      请试试这个。此查询可用于日期比较

      select * from [User] U where convert(varchar(10),U.DateCreated, 120) = '2014-02-07'
      

      【讨论】:

        【解决方案6】:

        您可以使用LIKE 语句代替=。但是要使用 DateStamp 执行此操作,您需要先将 CONVERT 发送到 VARCHAR:

        SELECT * 
        FROM [User] U
        WHERE CONVERT(VARCHAR, U.DateCreated, 120) LIKE '2014-02-07%'
        

        【讨论】:

        • +1 因为这是一个可行的解决方案,并且可以在许多情况下使用,请不要仅仅因为您觉得这不是一个好的做法而对可行的答案投反对票,请为我们提供可靠的文章或 doc,那么您更能说服我们
        • @Ahmad 字符串转换然后进行比较比日期比较更昂贵。因此,反对票是有道理的,因为这不是做 OP 想做的事情的好方法。
        猜你喜欢
        • 2016-10-08
        • 2010-09-05
        • 2013-06-28
        • 2016-07-24
        • 1970-01-01
        • 2013-09-16
        • 2014-05-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多