查询昨日00:00至23:59数据的SQL语句有效性及优化方案咨询
原SQL语句的有效性分析
好问题!先直接给结论:你这条SQL语句完全可以精准获取昨日00:00至23:59的所有数据,咱们来拆解下逻辑:
你的passDate是datetime类型,原语句里的条件拆解后是:
convert(date, GETDATE())会把当前时间截断为纯日期(比如当前是2024-05-20 15:40:00,转成date就是2024-05-20)DATEADD(DAY, -1, convert(date, GETDATE()))得到的是昨天的纯日期,和datetime类型比较时会自动隐式转为yyyy-MM-dd 00:00:00.000- 右边的
passDate < convert(date, GETDATE())等价于passDate < 'yyyy-MM-dd 00:00:00.000'(今天的零点),这就覆盖了昨天所有datetime值——因为SQL Server的datetime精度是3.33毫秒,昨天最晚的有效datetime是yyyy-MM-dd 23:59:59.997,完全符合你“含两端时间”的需求。
更优的实现方式
原语句已经很规范了,但可以根据场景选择更简洁、通用或高效的写法:
1. 用CAST替代CONVERT(ANSI标准,跨库兼容)
CAST是SQL的ANSI标准函数,比CONVERT的跨数据库兼容性更好(比如PostgreSQL、MySQL也支持类似用法),写法更简洁:
SELECT * FROM table WHERE passDate >= DATEADD(DAY, -1, CAST(GETDATE() AS DATE)) AND passDate < CAST(GETDATE() AS DATE)
(注:date转datetime是隐式转换,所以不用额外CAST,代码更清爽)
2. 用DATEFROMPARTS构造日期(SQL Server 2012+,可读性拉满)
如果你的SQL Server版本是2012及以上,DATEFROMPARTS可以直观构造昨天的日期,代码可读性更强:
DECLARE @Yesterday DATE = DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), DAY(GETDATE()) - 1) DECLARE @Today DATE = CAST(GETDATE() AS DATE) SELECT * FROM table WHERE passDate >= @Yesterday AND passDate < @Today
把日期赋值给变量的好处是:复杂查询里不用重复计算日期,代码逻辑更清晰。
3. 避免重复计算当前日期(小性能优化)
如果不想用变量,也可以用子查询先算出当前日期,减少函数调用次数:
SELECT * FROM table CROSS JOIN (SELECT CAST(GETDATE() AS DATE) AS Today) AS Dates WHERE passDate >= DATEADD(DAY, -1, Dates.Today) AND passDate < Dates.Today
这种写法在多表关联或复杂查询里更高效,因为Today只计算一次。
重要提醒:避开性能陷阱
绝对不要写成下面这种形式——因为函数直接作用在passDate列上,会导致passDate上的索引失效(只能做全表扫描,性能暴跌):
-- 不推荐!索引失效风险极高 SELECT * FROM table WHERE CAST(passDate AS DATE) = DATEADD(DAY, -1, CAST(GETDATE() AS DATE))
你的原语句是对常量做计算,列保持原始值,所以能正常使用索引,这一点做得非常棒!
内容的提问来源于stack exchange,提问作者Vicky
相关产品推荐
相关产品推荐

