MySQL周日期查询之精准获取上周/本周的周一和周日全攻略

 更新时间:2026年03月24日 08:50:14   作者:python全栈小辉  
这篇文章主要介绍了MySQL中精准获取上周/本周周一和周日的SQL实现方法,文中的示例代码讲解详细,有需要的小伙伴可以跟随小编一起学习一下

在业务开发中,“查询上周/本周的周一、周日”是非常高频的需求:比如统计上周的销售数据、生成本周的排班表、按周汇总报表等。但很多开发者在写这类SQL时容易踩坑:要么搞混MySQL中周的定义(周一还是周日为一周第一天),要么边界情况处理错误(比如当前是周一/周日时结果不对),导致查询的数据范围不准确。

MySQL提供了丰富的日期处理函数,但不同函数对周的定义差异很大,选错函数或逻辑会直接导致结果错误。本文将从MySQL周的定义出发,全面讲解如何精准获取上周的周一、上周的周日、本周的周一、本周的周日,所有SQL均经过多场景验证,同时提供不同周定义下的适配方案,帮助你一次性写对周日期查询SQL。

一、前置知识:MySQL中周的核心定义

在开始写SQL之前,必须先明确MySQL中两个最常用的周相关函数的定义,这是90%的错误根源:

1.1 两个核心周函数的区别

函数返回值范围对应星期核心特点
WEEKDAY(date)0-60=周一, 1=周二, …, 6=周日国内常用,以周一为一周第一天
DAYOFWEEK(date)1-71=周日, 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:0123: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日期查询的资料请关注脚本之家其它相关文章!

相关文章

  • MySQL双主高可用详解

    MySQL双主高可用详解

    文章介绍了在CentOS7.9上部署MySQL双主架构及Keepalived高可用方案,涵盖主机规划、系统优化、MySQL自动安装、主从同步配置和Keepalived部署步骤,强调版本兼容性与脚本执行要求
    2025-08-08
  • mysql深度分页的几种解决方案

    mysql深度分页的几种解决方案

    MySQL深分页需避免OFFSET,改用WHERE条件定位起点,常用游标分页、延迟关联或覆盖索引优化,结合缓存可提升性能,本文主要介绍了mysql深度分页的几种解决方案,感兴趣的可以了解一下
    2025-09-09
  • MySQL数据库备份工具mylvmbackup的使用解读

    MySQL数据库备份工具mylvmbackup的使用解读

    这篇文章主要介绍了MySQL数据库备份工具mylvmbackup的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-05-05
  • MySQL表的增删改查基础教程

    MySQL表的增删改查基础教程

    这篇文章主要给大家介绍了关于MySQL表的增删改查的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • MySQL 5.6下table_open_cache参数优化合理配置详解

    MySQL 5.6下table_open_cache参数优化合理配置详解

    这篇文章主要介绍了MySQL 5.6下table_open_cache参数合理配置详解,需要的朋友可以参考下
    2018-03-03
  • MySql中modify、rename、change的使用及区别

    MySql中modify、rename、change的使用及区别

    这篇文章主要介绍了MySql中modify、rename、change的使用及区别,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • mysql查询的时候给字段赋默认值操作

    mysql查询的时候给字段赋默认值操作

    这篇文章主要介绍了mysql查询的时候给字段赋默认值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • mysql根据逗号将一行数据拆分成多行数据

    mysql根据逗号将一行数据拆分成多行数据

    本文主要介绍了mysql根据逗号将一行数据拆分成多行数据,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • 在MySQL的InnoDB存储引擎中的Doublewrite Buffer详解

    在MySQL的InnoDB存储引擎中的Doublewrite Buffer详解

    DoublewriteBuffer是InnoDB为防止部分写失败导致的数据损坏而设计的机制,通过先将脏页写入内存缓冲区再同步到磁盘,配合redolog实现崩溃恢复,确保数据完整性和可靠性
    2025-08-08
  • percona-toolkit之pt-kill 杀掉mysql查询或连接的方法

    percona-toolkit之pt-kill 杀掉mysql查询或连接的方法

    本文主要描述了percona-toolkit中pt-kill的 使用实例 ,及 一些重要参数的介绍,需要的朋友可以参考下
    2016-04-04

最新评论