当前位置:首页 > 问答 > 正文

MSSQL里怎么用小于符号比较时间啊,感觉有点绕不过去的地方想搞明白

时间其实都是“日期时间”

在MSSQL里,没有一个单独的、只存储“几点几分”的“时间”数据类型,我们最常用的 DATETIMEDATETIME2SMALLDATETIME 这些类型,全都是既存日期又存时间的。2023-10-27 15:30:00,前面的 2023-10-27 是日期,后面的 15:30:00 是时间。

当你直接用小于符号(<)比较两个这种带日期的时间时,数据库是连日期带时间一起比较的,这很符合直觉, ‘2023-10-27 10:00:00’ < ‘2023-10-27 15:00:00’ 这个比较的结果肯定是“真”(True),因为27号10点确实早于27号15点。

让你感觉“绕”的地方可能在这里:

  1. 你想忽略日期,只比较时间部分:你有一张表记录着员工打卡时间,你想找出所有在上午9点之前打卡的记录,你的直觉可能是写: SELECT * FROM 打卡记录 WHERE 打卡时间 < ‘09:00:00’ 但这么写很可能不对,或者结果很奇怪,为什么呢?因为你的“打卡时间”字段是 DATETIME 类型的,存的是像 2023-10-27 08:30:00 这样的完整值,而你这个写法里的 ‘09:00:00’,MSSQL会怎么理解呢?它会自动补上一个默认的日期,通常是 1900-01-01,你的查询条件就变成了: 打卡时间 < ‘1900-01-01 09:00:00’ 你表里的记录日期都是2023年,怎么可能小于1900年呢?所以这个查询很可能一条记录都查不出来。

    MSSQL里怎么用小于符号比较时间啊,感觉有点绕不过去的地方想搞明白

  2. 时间精度问题DATETIME 类型的最小精度是百分之三秒(3.33毫秒),而 DATETIME2 可以更精确,如果你在比较时,字面值的时间格式没有写对,或者因为精度问题导致两个看起来相等的时间实际上因为微小的毫秒差而比较失败,也会让人觉得“绕”。

那到底该怎么正确地用小于符号比较时间呢?

关键在于,把日期部分“抹掉”或者“标准化”,让比较只在时间部分进行,这里有几种常见的方法:

使用 CONVERT 或 CAST 函数提取时间部分

MSSQL里怎么用小于符号比较时间啊,感觉有点绕不过去的地方想搞明白

这是最直接、最常用的方法,思路是把 DATETIME 类型的字段转换成只包含时间的字符串,然后再和另一个时间字符串比较。

  • CONVERT 函数:MSSQL提供了很多标准的时间格式码。 SELECT * FROM 打卡记录 WHERE CONVERT(VARCHAR(8), 打卡时间, 108) < ‘09:00:00’ 这里,108 是格式码,代表 ‘HH:MI:SS’(时分秒)。CONVERT(VARCHAR(8), 打卡时间, 108) 会把 2023-10-27 08:30:00 变成字符串 ‘08:30:00’,再用这个字符串和 ‘09:00:00’ 比较,就是纯粹的字符串比较了,完全符合你的预期。

  • CAST 函数:也可以先将字段转为 TIME 类型(MSSQL2008及以上版本支持)。TIME 类型是只存储时间部分的。 SELECT * FROM 打卡记录 WHERE CAST(打卡时间 AS TIME) < ‘09:00:00’ 这种方法更现代,也更易读。

通过日期函数“构造”比较值

MSSQL里怎么用小于符号比较时间啊,感觉有点绕不过去的地方想搞明白

另一种思路是,不改变字段本身,而是把一个纯时间“挂”到某个统一的、不会影响比较结果的日期上。

你可以取字段当天的日期,然后加上你想比较的目标时间,构造出一个完整的 DATETIME,再和原字段比较。 SELECT * FROM 打卡记录 WHERE 打卡时间 < CAST(CAST(GETDATE() AS DATE) AS DATETIME) + CAST(‘09:00:00’ AS DATETIME) 这个语句看起来复杂,分解一下:

  • GETDATE() 取当前日期时间。
  • CAST(GETDATE() AS DATE) 只取当前日期部分,时间变为00:00:00。
  • CAST(... AS DATETIME) 转回DATETIME(确保类型一致)。
  • CAST(‘09:00:00’ AS DATETIME) 把你的目标时间转成DATETIME(日期会是1900-01-01)。
  • 两者相加,得到的是今天日期加上9点钟的时间,2023-10-27 09:00:00
  • 最后用这个构造出的时间和原字段比较:打卡时间 < ‘2023-10-27 09:00:00’。 由于日期部分相同,比较的就是时间部分了,这种方法适用于和你“的某个时间点比较。

计算时间间隔(适用于时间差比较)

有时候你想找的是“距离现在超过1小时”的记录,这时候用小于符号比较的是时间间隔。 SELECT * FROM 订单表 WHERE DATEADD(HOUR, 1, 下单时间) < GETDATE() 这句的意思是:给“下单时间”加上1小时,如果这个时间点小于当前时间,就说明下单时间距离现在已经超过1小时了,这里小于符号比较的仍然是完整的日期时间,但逻辑上实现的是时间间隔的判断。

你觉得绕,根本原因是数据类型在“作怪”,MSSQL里的时间总是和日期绑在一起,用小于符号比较时,一定要清醒地知道你在比较的是什么。

  • 如果要纯粹比较时间部分(忽略日期):优先使用 CAST(你的字段 AS TIME) < ‘目标时间’
  • 如果要在同一天内比较:可以构造一个日期相同、时间不同的值来比较。
  • 如果要比较时间间隔:用 DATEADD 等函数来处理。

理解了“日期时间”是一个不可分割的整体这个前提,再掌握一两种“剥离”日期只比时间的方法,这个弯就绕过来了,实际工作中,方法一 里的两种转换方式是最常用、最不容易出错的。