between本身支持跨年,失效主因是字段类型非日期型、字符串格式不标准、隐式转换或函数误用;应统一用iso格式'yyyy-mm-dd'并确保字段为date/datetime类型。

WHERE条件里用BETWEEN会跨年失效吗?
会,但不是函数的问题,是日期字符串格式或类型隐式转换导致的。比如BETWEEN '2023-12-25' AND '2024-01-05'本身完全合法,MySQL、PostgreSQL、SQL Server都支持跨年范围。真正出问题的往往是:
- 字段类型是
CHAR或VARCHAR,存的是'25/12/2023'这类非标准格式,排序按字符串比,'05/01/2024'会排在'25/12/2023'前面 - 应用层拼接SQL时没加单引号,变成
BETWEEN 2023-12-25 AND 2024-01-05,数据库当减法算,结果是BETWEEN 2006 AND 2018 - 使用
STR_TO_DATE()(MySQL)或TO_DATE()(Oracle)时格式符写错,比如把'%d/%m/%Y'写成'%m/%d/%Y',跨年数据全错位
建议统一用ISO标准格式'YYYY-MM-DD',且确保字段是DATE或DATETIME类型。
PostgreSQL里date_part('year', col)不能直接用于跨年范围筛选
date_part('year', col)只返回年份数字,丢失月日信息,没法表达“2023年12月到2024年2月”这种区间。常见错误写法:
WHERE date_part('year', order_date) IN (2023, 2024)
这会查出2023全年+2024全年,而不是你想要的连续14天。
正确做法是用原生日期比较:
WHERE order_date >= '2023-12-01' AND order_date <p>或者用<code>GENERATE_SERIES()</code>配合<code>OVERLAPS</code>(高级场景),但日常够用的永远是直接范围比较。</p><h3>SQL Server的DATEADD和DATEDIFF在跨年计算时要注意时区和边界</h3><p><code>DATEADD</code>本身不跨年出错,但和<code>GETDATE()</code>连用时容易踩坑。例如想查“过去90天”,写成:</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/ai/1960" title="小羊标书"><img src="https://img.php.cn/upload/ai_manual/000/000/000/175680456053464.png" alt="小羊标书" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/ai/1960" title="小羊标书" class="overflowclass">小羊标书</a> <p class="overflowclass">一键生成百页标书,让投标更简单高效</p> </div> <a rel="nofollow" href="/ai/1960" title="小羊标书" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div><pre class="brush:php;toolbar:false;">WHERE order_date >= DATEADD(day, -90, GETDATE())
看起来没问题,但如果order_date是DATETIME2(7)而GETDATE()是DATETIME(精度低),SQL Server可能因类型隐式转换丢掉毫秒级精度,导致边界日数据漏掉。
更稳妥的是显式转成同类型:
WHERE order_date >= DATEADD(day, -90, CAST(GETDATE() AS DATETIME2))
另外,DATEDIFF(year, ...)会忽略月日,DATEDIFF(year, '2023-12-31', '2024-01-01')返回1,但实际只差1天——跨年统计别用这个函数算“整年”。
MySQL中CURDATE() + INTERVAL跨年要防溢出
CURDATE() + INTERVAL 1 MONTH在1月31日执行,结果是2024-02-29(如果当年是闰年)或2024-02-28(非闰年),不会报错,但可能不符合业务预期。比如你本意是“下个月最后一天”,结果得到2月28日,而3月有31天。
更可控的方式是用LAST_DAY():
SELECT LAST_DAY(CURDATE() + INTERVAL 1 MONTH)
它总返回目标月份的最后一天,不管当月多少天。跨年时也一样:12月31日执行,得到LAST_DAY('2024-01-31') → '2024-01-31',而不是'2024-02-29'。
跨年本身不难,难的是日期字段类型、格式、精度、时区这些细节堆在一起时,某一处松动就让结果偏移几天。










