在业务开发中,“查询上周/本周的周一、周日”是非常高频的需求:比如统计上周的销售数据、生成本周的排班表、按周汇总报表等。但很多开发者在写这类sql时容易踩坑:要么搞混mysql中周的定义(周一还是周日为一周第一天),要么边界情况处理错误(比如当前是周一/周日时结果不对),导致查询的数据范围不准确。
mysql提供了丰富的日期处理函数,但不同函数对周的定义差异很大,选错函数或逻辑会直接导致结果错误。本文将从mysql周的定义出发,全面讲解如何精准获取上周的周一、上周的周日、本周的周一、本周的周日,所有sql均经过多场景验证,同时提供不同周定义下的适配方案,帮助你一次性写对周日期查询sql。
一、前置知识:mysql中周的核心定义
在开始写sql之前,必须先明确mysql中两个最常用的周相关函数的定义,这是90%的错误根源:
1.1 两个核心周函数的区别
| 函数 | 返回值范围 | 对应星期 | 核心特点 |
|---|---|---|---|
| weekday(date) | 0-6 | 0=周一, 1=周二, …, 6=周日 | 国内常用,以周一为一周第一天 |
| dayofweek(date) | 1-7 | 1=周日, 2=周一, …, 7=周六 | 欧美常用,以周日为一周第一天 |
核心结论:本文默认采用**国内业务最常用的“周一为一周第一天”**的定义,基于weekday()函数实现;如果你的业务以周日为一周第一天,请看本文第四章的适配方案。
1.2 本文的时间基准
所有sql均以curdate()(当前日期)为基准,你可以将curdate()替换为任意日期字段(比如create_time)或具体日期(比如'2026-03-23'),灵活适配不同场景。
二、核心需求实现:精准获取上周/本周的周一、周日
2.1 获取本周的周一(最基础、最常用)
核心逻辑
- 用
weekday(curdate())获取当前日期是星期几(0=周一); - 用
date_sub()减去对应的天数,即可得到本周的周一:- 如果今天是周一(weekday=0):减0天,就是今天;
- 如果今天是周二(weekday=1):减1天,回到周一;
- …
- 如果今天是周日(weekday=6):减6天,回到本周一。
sql语句
-- 获取本周的周一(周一为一周第一天) select date_sub(curdate(), interval weekday(curdate()) day) as 本周一;
示例验证
假设当前日期是2026-03-25(周三):
weekday('2026-03-25')返回2(周三);date_sub('2026-03-25', interval 2 day)返回2026-03-23(周一),结果正确。
2.2 获取本周的周日
核心逻辑
- 先按2.1的方法获取本周的周一;
- 本周的周一加上6天,就是本周的周日(周一+1天=周二,…,+6天=周日)。
sql语句
-- 获取本周的周日(周一为一周第一天) select date_add(date_sub(curdate(), interval weekday(curdate()) day), interval 6 day) as 本周日;
简化写法(更直观)
-- 用date_sub的负数等价于date_add,写法更简洁 select date_sub(curdate(), interval weekday(curdate()) - 6 day) as 本周日;
示例验证
假设当前日期是2026-03-25(周三):
- 本周一是
2026-03-23; - 加6天得到
2026-03-29(周日),结果正确。
2.3 获取上周的周一
核心逻辑
- 先按2.1的方法获取本周的周一;
- 本周的周一减去7天,就是上周的周一。
sql语句
-- 获取上周的周一(周一为一周第一天) select date_sub(date_sub(curdate(), interval weekday(curdate()) day), interval 7 day) as 上周一;
示例验证
假设当前日期是2026-03-25(周三):
- 本周一是
2026-03-23; - 减7天得到
2026-03-16(上周的周一),结果正确。
2.4 获取上周的周日(最巧妙的写法)
核心逻辑
这里有一个非常巧妙的逻辑,不需要先算上周一再算上周日:
- 先按2.1的方法获取本周的周一;
- 本周的周一减去1天,就是上周的周日(本周一的前一天,自然是上周的最后一天)。
sql语句
-- 获取上周的周日(周一为一周第一天,推荐写法) select date_sub(date_sub(curdate(), interval weekday(curdate()) day), interval 1 day) as 上周日;
示例验证
假设当前日期是2026-03-25(周三):
- 本周一是
2026-03-23; - 减1天得到
2026-03-22(上周的周日),结果正确。
边界情况验证
如果当前日期是2026-03-23(周一):
- 本周一是
2026-03-23; - 减1天得到
2026-03-22(上周的周日),结果依然正确。
三、实战场景:结合业务查询周数据
掌握了基础的周日期获取后,我们结合实际业务场景,看看如何用这些sql查询周数据。
3.1 场景一:查询上周的所有订单数据
需求
查询order_info表中,上周周一00:00:00到上周日23:59:59的所有订单。
sql语句
-- 定义上周的开始和结束时间 set @last_monday = date_sub(date_sub(curdate(), interval weekday(curdate()) day), interval 7 day); set @last_sunday = date_sub(date_sub(curdate(), interval weekday(curdate()) day), interval 1 day); -- 查询上周的订单(时间范围:上周一00:00:00 到 上周日23:59:59) select * from order_info where create_time >= @last_monday and create_time < date_add(@last_sunday, interval 1 day);
注意:用< 上周日+1天代替<= 上周日23:59:59,可以避免处理时间的时分秒,更简洁且不会遗漏数据。
3.2 场景二:查询本周的用户注册数据
需求
查询user_info表中,本周一到今天的新增用户数(按天分组)。
sql语句
-- 定义本周一 set @this_monday = date_sub(curdate(), interval weekday(curdate()) day); -- 查询本周一到今天的新增用户,按天分组 select date(create_time) as 日期, count(*) as 新增用户数 from user_info where create_time >= @this_monday and create_time < date_add(curdate(), interval 1 day) group by date(create_time) order by 日期;
3.3 场景三:生成上周和本周的日期范围
需求
一次性获取上周和本周的周一、周日,生成报表的日期范围。
sql语句
select -- 上周 date_sub(date_sub(curdate(), interval weekday(curdate()) day), interval 7 day) as 上周一, date_sub(date_sub(curdate(), interval weekday(curdate()) day), interval 1 day) as 上周日, -- 本周 date_sub(curdate(), interval weekday(curdate()) day) as 本周一, date_add(date_sub(curdate(), interval weekday(curdate()) day), interval 6 day) as 本周日;
四、适配方案:以周日为一周第一天的写法
如果你的业务采用**欧美常用的“周日为一周第一天”**的定义(比如国际业务、外企系统),可以用dayofweek()函数实现,逻辑类似,只是调整了天数计算。
4.1 核心函数说明
dayofweek(date)返回1-7,对应:
1=周日, 2=周一, …, 7=周六
4.2 完整sql(周日为一周第一天)
select -- 上周日(上周的第一天) date_sub(curdate(), interval dayofweek(curdate()) - 1 day) - interval 7 day as 上周日, -- 上周六(上周的最后一天) date_sub(curdate(), interval dayofweek(curdate()) day) as 上周六, -- 本周日(本周的第一天) date_sub(curdate(), interval dayofweek(curdate()) - 1 day) as 本周日, -- 本周六(本周的最后一天) date_add(date_sub(curdate(), interval dayofweek(curdate()) - 1 day), interval 6 day) as 本周六;
五、避坑指南:90%的人都会犯的周日期错误
5.1 坑一:搞混weekday和dayofweek的定义
很多人不看函数文档,想当然认为weekday的0是周日,或者dayofweek的1是周一,导致结果差了一天。
避坑方案:
- 用之前先测试一下函数返回值:
select weekday(curdate()), dayofweek(curdate()); - 本文的sql默认用
weekday(周一为第一天),如果用dayofweek请看第四章。
5.2 坑二:处理时间范围时遗漏时分秒
查询周数据时,用create_time <= 上周日会遗漏上周日当天的00:00:01到23:59:59的数据,因为create_time通常是datetime类型,包含时分秒。
避坑方案:
- 用
< 上周日+1天代替<= 上周日,自动包含上周日的所有时间; - 或者显式拼接时分秒:
create_time <= concat(@last_sunday, ' 23:59:59')。
5.3 坑三:边界情况处理错误
比如当前是周一的时候,获取“本周的周一”应该是今天,获取“上周的周日”应该是昨天;当前是周日的时候,获取“本周的周日”应该是今天。
避坑方案:
- 用本文提供的sql,已经经过边界情况验证;
- 测试时用具体的边界日期验证:比如
curdate()替换为'2026-03-23'(周一)、'2026-03-29'(周日)。
5.4 坑四:不同mysql版本的week模式差异
mysql的week()函数有多种模式,但本文用的是weekday()和dayofweek(),这两个函数在所有mysql版本(5.7、8.0、8.4)中的定义都是一致的,没有版本差异,可以放心使用。
六、总结:周日期查询速查表
为了方便大家直接复制使用,我们整理了周一为一周第一天的速查表:
| 需求 | sql语句 |
|---|---|
| 获取本周的周一 | date_sub(curdate(), interval weekday(curdate()) day) |
| 获取本周的周日 | date_add(date_sub(curdate(), interval weekday(curdate()) day), interval 6 day) |
| 获取上周的周一 | date_sub(date_sub(curdate(), interval weekday(curdate()) day), interval 7 day) |
| 获取上周的周日 | date_sub(date_sub(curdate(), interval weekday(curdate()) day), interval 1 day) |
核心结论:
- 优先明确周的定义(周一还是周日为第一天),国内业务默认用周一;
- 基于
weekday()函数的逻辑最直观,且经过多场景验证; - 查询时间范围时,用
< 结束日期+1天避免遗漏时分秒; - 所有sql都可以将
curdate()替换为任意日期字段,灵活适配业务。
以上就是mysql周日期查询之精准获取上周/本周的周一和周日全攻略的详细内容,更多关于mysql日期查询的资料请关注代码网其它相关文章!
发表评论