如何编写忽略年份、仅按日月范围筛选记录的SQL查询
SQL跨年份筛选指定月日范围实现方案
以下是不同场景下的常用实现方案,覆盖主流数据库兼容、性能优化、特殊边界处理等需求:
方案1:月日字符串拼接比较(全数据库通用兼容)
该方案不受数据库类型限制,ymd字段为DATE类型或标准YYYY-MM-DD格式字符串都可以直接使用:
- 核心逻辑:把日期的月份、日期提取后拼接为
MM-DD格式的字符串,利用MM-DD字符串的字典序和时间顺序一致的特性,直接和目标范围比较 - 示例SQL(筛选每年5月12日到7月12日):
SELECT * FROM 你的表名 WHERE DATE_FORMAT(ymd, '%m-%d') BETWEEN '05-12' AND '07-12';
不同数据库的日期格式化函数差异:
- PostgreSQL 替换为
TO_CHAR(ymd, 'MM-DD')- SQL Server 替换为
FORMAT(ymd, 'MM-dd')或CONVERT(VARCHAR(5), ymd, 10)- SQLite 替换为
STRFTIME('%m-%d', ymd)
方案2:月日数值拆分判断(性能更优)
如果数据量较大,不想每次查询都执行字符串格式化计算,可以直接拆分月份、日期做逻辑判断,搭配预先建立的月日计算字段/函数索引可以大幅提升查询性能:
SELECT * FROM 你的表名 WHERE (MONTH(ymd) = 5 AND DAY(ymd) >= 12) OR (MONTH(ymd) = 6) OR (MONTH(ymd) = 7 AND DAY(ymd) <= 12);
不同数据库的月日提取函数差异:
- PostgreSQL 替换为
EXTRACT(MONTH FROM ymd)、EXTRACT(DAY FROM ymd)- SQL Server 替换为
DATEPART(MONTH, ymd)、DATEPART(DAY, ymd)- SQLite 替换为
CAST(STRFTIME('%m', ymd) AS INTEGER)、CAST(STRFTIME('%d', ymd) AS INTEGER)
特殊场景:跨年末的月日范围处理
如果要筛选的范围跨年末,比如每年12月20日到次年1月10日,上述两种方案的BETWEEN写法会失效,调整判断逻辑即可:
-- 以通用兼容方案为例调整 SELECT * FROM 你的表名 WHERE DATE_FORMAT(ymd, '%m-%d') >= '12-20' OR DATE_FORMAT(ymd, '%m-%d') <= '01-10';
优化建议
- 如果这类查询是高频需求,建议新增一个
mmdd计算列存储MM-DD格式内容并建立索引,查询时直接匹配该字段,性能远高于每次查询做实时函数计算 - 如果
ymd是字符串类型,务必保证存储格式为标准YYYY-MM-DD,否则所有日期函数都会失效,建议提前转成DATE类型存储
内容的提问来源于stack exchange,提问作者Vi Ha
相关产品推荐
相关产品推荐

