MSSQL特定日期COUNT查询返回0,BETWEEN查询正常问题求助
哈哈,这个问题我之前帮朋友排查过,简直是跨数据库开发的经典坑!核心问题出在MSSQL和MySQL对日期字符串的解析逻辑不一样,而且你那个BETWEEN能查到结果其实是个巧合~
为什么会出现这种奇怪的现象?
1. 日期字符串的解析差异
MySQL对日期字符串的兼容性更强,会根据上下文自动识别你写的'08-06-2020'是日-月-年(也就是2020年8月6日);但MSSQL默认是按照月-日-年的规则解析这种短横线分隔的字符串,所以它会把'08-06-2020'当成2020年6月8日。如果你的数据实际是2020年8月6日的记录,那=查询自然返回0啦。
2. BETWEEN的“意外生效”
你写的BETWEEN '08-06-2020' AND '07-06-2020',MSSQL会先把这两个字符串转成日期值:'08-06-2020'→2020-06-08,'07-06-2020'→2020-06-07。因为BETWEEN要求左值必须小于等于右值,MSSQL会自动交换两个值的顺序,实际执行的是BETWEEN '2020-06-07' AND '2020-06-08',刚好你的数据落在这个区间里,所以返回了正确结果——这完全是个巧合,可不是正确的写法哦!
怎么解决这个问题?
要彻底避免这种格式歧义,推荐这几种做法:
方法1:用ISO标准日期格式(最稳妥)
MSSQL会优先识别yyyy-MM-dd格式的日期字符串,不受任何默认设置影响,跨数据库也通用:
-- 如果要查2020年8月6日,就写: SELECT COUNT(*) from dbo.SchDetail WHERE dbSchDate = '2020-08-06'; -- 如果要查2020年6月8日,就写: SELECT COUNT(*) from dbo.SchDetail WHERE dbSchDate = '2020-06-08';
方法2:显式指定日期格式
用CONVERT函数明确告诉MSSQL你的日期格式,比如日-月-年对应的格式代码是103:
-- 解析'08-06-2020'为2020年8月6日 SELECT COUNT(*) from dbo.SchDetail WHERE dbSchDate = CONVERT(DATE, '08-06-2020', 103);
方法3:处理带时间的datetime字段
如果你的dbSchDate是datetime类型(包含时分秒),直接用=匹配日期字符串只会匹配时间为00:00:00的记录,这时候应该用范围查询来覆盖全天:
-- 查询2020年8月6日全天的所有记录 SELECT COUNT(*) from dbo.SchDetail WHERE dbSchDate >= CONVERT(DATE, '08-06-2020', 103) AND dbSchDate < DATEADD(DAY, 1, CONVERT(DATE, '08-06-2020', 103));
额外提醒
跨数据库开发时,千万不要依赖数据库的默认日期解析规则,明确的格式才是避免踩坑的关键。另外,如果表结构允许,尽量把日期字段设置为DATE或DATETIME2类型,不要存成字符串,这样能从根源上减少格式转换的问题。
内容的提问来源于stack exchange,提问作者l0tze

