MySQL周日期查詢之精準(zhǔn)獲取上周/本周的周一和周日全攻略
在業(yè)務(wù)開(kāi)發(fā)中,“查詢上周/本周的周一、周日”是非常高頻的需求:比如統(tǒng)計(jì)上周的銷(xiāo)售數(shù)據(jù)、生成本周的排班表、按周匯總報(bào)表等。但很多開(kāi)發(fā)者在寫(xiě)這類(lèi)SQL時(shí)容易踩坑:要么搞混MySQL中周的定義(周一還是周日為一周第一天),要么邊界情況處理錯(cuò)誤(比如當(dāng)前是周一/周日時(shí)結(jié)果不對(duì)),導(dǎo)致查詢的數(shù)據(jù)范圍不準(zhǔn)確。
MySQL提供了豐富的日期處理函數(shù),但不同函數(shù)對(duì)周的定義差異很大,選錯(cuò)函數(shù)或邏輯會(huì)直接導(dǎo)致結(jié)果錯(cuò)誤。本文將從MySQL周的定義出發(fā),全面講解如何精準(zhǔn)獲取上周的周一、上周的周日、本周的周一、本周的周日,所有SQL均經(jīng)過(guò)多場(chǎng)景驗(yàn)證,同時(shí)提供不同周定義下的適配方案,幫助你一次性寫(xiě)對(duì)周日期查詢SQL。
一、前置知識(shí):MySQL中周的核心定義
在開(kāi)始寫(xiě)SQL之前,必須先明確MySQL中兩個(gè)最常用的周相關(guān)函數(shù)的定義,這是90%的錯(cuò)誤根源:
1.1 兩個(gè)核心周函數(shù)的區(qū)別
| 函數(shù) | 返回值范圍 | 對(duì)應(yīng)星期 | 核心特點(diǎn) |
|---|---|---|---|
| WEEKDAY(date) | 0-6 | 0=周一, 1=周二, …, 6=周日 | 國(guó)內(nèi)常用,以周一為一周第一天 |
| DAYOFWEEK(date) | 1-7 | 1=周日, 2=周一, …, 7=周六 | 歐美常用,以周日為一周第一天 |
核心結(jié)論:本文默認(rèn)采用**國(guó)內(nèi)業(yè)務(wù)最常用的“周一為一周第一天”**的定義,基于WEEKDAY()函數(shù)實(shí)現(xiàn);如果你的業(yè)務(wù)以周日為一周第一天,請(qǐng)看本文第四章的適配方案。
1.2 本文的時(shí)間基準(zhǔn)
所有SQL均以CURDATE()(當(dāng)前日期)為基準(zhǔn),你可以將CURDATE()替換為任意日期字段(比如create_time)或具體日期(比如'2026-03-23'),靈活適配不同場(chǎng)景。
二、核心需求實(shí)現(xiàn):精準(zhǔn)獲取上周/本周的周一、周日
2.1 獲取本周的周一(最基礎(chǔ)、最常用)
核心邏輯
- 用
WEEKDAY(CURDATE())獲取當(dāng)前日期是星期幾(0=周一); - 用
DATE_SUB()減去對(duì)應(yīng)的天數(shù),即可得到本周的周一:- 如果今天是周一(WEEKDAY=0):減0天,就是今天;
- 如果今天是周二(WEEKDAY=1):減1天,回到周一;
- …
- 如果今天是周日(WEEKDAY=6):減6天,回到本周一。
SQL語(yǔ)句
-- 獲取本周的周一(周一為一周第一天) SELECT DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) AS 本周一;
示例驗(yàn)證
假設(shè)當(dāng)前日期是2026-03-25(周三):
WEEKDAY('2026-03-25')返回2(周三);DATE_SUB('2026-03-25', INTERVAL 2 DAY)返回2026-03-23(周一),結(jié)果正確。
2.2 獲取本周的周日
核心邏輯
- 先按2.1的方法獲取本周的周一;
- 本周的周一加上6天,就是本周的周日(周一+1天=周二,…,+6天=周日)。
SQL語(yǔ)句
-- 獲取本周的周日(周一為一周第一天) SELECT DATE_ADD(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY), INTERVAL 6 DAY) AS 本周日;
簡(jiǎn)化寫(xiě)法(更直觀)
-- 用DATE_SUB的負(fù)數(shù)等價(jià)于DATE_ADD,寫(xiě)法更簡(jiǎn)潔 SELECT DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) - 6 DAY) AS 本周日;
示例驗(yàn)證
假設(shè)當(dāng)前日期是2026-03-25(周三):
- 本周一是
2026-03-23; - 加6天得到
2026-03-29(周日),結(jié)果正確。
2.3 獲取上周的周一
核心邏輯
- 先按2.1的方法獲取本周的周一;
- 本周的周一減去7天,就是上周的周一。
SQL語(yǔ)句
-- 獲取上周的周一(周一為一周第一天) SELECT DATE_SUB(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY), INTERVAL 7 DAY) AS 上周一;
示例驗(yàn)證
假設(shè)當(dāng)前日期是2026-03-25(周三):
- 本周一是
2026-03-23; - 減7天得到
2026-03-16(上周的周一),結(jié)果正確。
2.4 獲取上周的周日(最巧妙的寫(xiě)法)
核心邏輯
這里有一個(gè)非常巧妙的邏輯,不需要先算上周一再算上周日:
- 先按2.1的方法獲取本周的周一;
- 本周的周一減去1天,就是上周的周日(本周一的前一天,自然是上周的最后一天)。
SQL語(yǔ)句
-- 獲取上周的周日(周一為一周第一天,推薦寫(xiě)法) SELECT DATE_SUB(DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY), INTERVAL 1 DAY) AS 上周日;
示例驗(yàn)證
假設(shè)當(dāng)前日期是2026-03-25(周三):
- 本周一是
2026-03-23; - 減1天得到
2026-03-22(上周的周日),結(jié)果正確。
邊界情況驗(yàn)證
如果當(dāng)前日期是2026-03-23(周一):
- 本周一是
2026-03-23; - 減1天得到
2026-03-22(上周的周日),結(jié)果依然正確。
三、實(shí)戰(zhàn)場(chǎng)景:結(jié)合業(yè)務(wù)查詢周數(shù)據(jù)
掌握了基礎(chǔ)的周日期獲取后,我們結(jié)合實(shí)際業(yè)務(wù)場(chǎng)景,看看如何用這些SQL查詢周數(shù)據(jù)。
3.1 場(chǎng)景一:查詢上周的所有訂單數(shù)據(jù)
需求
查詢order_info表中,上周周一00:00:00到上周日23:59:59的所有訂單。
SQL語(yǔ)句
-- 定義上周的開(kāi)始和結(jié)束時(shí)間 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); -- 查詢上周的訂單(時(shí)間范圍:上周一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,可以避免處理時(shí)間的時(shí)分秒,更簡(jiǎn)潔且不會(huì)遺漏數(shù)據(jù)。
3.2 場(chǎng)景二:查詢本周的用戶注冊(cè)數(shù)據(jù)
需求
查詢user_info表中,本周一到今天的新增用戶數(shù)(按天分組)。
SQL語(yǔ)句
-- 定義本周一 SET @this_monday = DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY); -- 查詢本周一到今天的新增用戶,按天分組 SELECT DATE(create_time) AS 日期, COUNT(*) AS 新增用戶數(shù) 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 場(chǎng)景三:生成上周和本周的日期范圍
需求
一次性獲取上周和本周的周一、周日,生成報(bào)表的日期范圍。
SQL語(yǔ)句
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 本周日;
四、適配方案:以周日為一周第一天的寫(xiě)法
如果你的業(yè)務(wù)采用**歐美常用的“周日為一周第一天”**的定義(比如國(guó)際業(yè)務(wù)、外企系統(tǒng)),可以用DAYOFWEEK()函數(shù)實(shí)現(xiàn),邏輯類(lèi)似,只是調(diào)整了天數(shù)計(jì)算。
4.1 核心函數(shù)說(shuō)明
DAYOFWEEK(date)返回1-7,對(duì)應(yīng):
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%的人都會(huì)犯的周日期錯(cuò)誤
5.1 坑一:搞混WEEKDAY和DAYOFWEEK的定義
很多人不看函數(shù)文檔,想當(dāng)然認(rèn)為WEEKDAY的0是周日,或者DAYOFWEEK的1是周一,導(dǎo)致結(jié)果差了一天。
避坑方案:
- 用之前先測(cè)試一下函數(shù)返回值:
SELECT WEEKDAY(CURDATE()), DAYOFWEEK(CURDATE()); - 本文的SQL默認(rèn)用
WEEKDAY(周一為第一天),如果用DAYOFWEEK請(qǐng)看第四章。
5.2 坑二:處理時(shí)間范圍時(shí)遺漏時(shí)分秒
查詢周數(shù)據(jù)時(shí),用create_time <= 上周日會(huì)遺漏上周日當(dāng)天的00:00:01到23:59:59的數(shù)據(jù),因?yàn)?code>create_time通常是DATETIME類(lèi)型,包含時(shí)分秒。
避坑方案:
- 用
< 上周日+1天代替<= 上周日,自動(dòng)包含上周日的所有時(shí)間; - 或者顯式拼接時(shí)分秒:
create_time <= CONCAT(@last_sunday, ' 23:59:59')。
5.3 坑三:邊界情況處理錯(cuò)誤
比如當(dāng)前是周一的時(shí)候,獲取“本周的周一”應(yīng)該是今天,獲取“上周的周日”應(yīng)該是昨天;當(dāng)前是周日的時(shí)候,獲取“本周的周日”應(yīng)該是今天。
避坑方案:
- 用本文提供的SQL,已經(jīng)經(jīng)過(guò)邊界情況驗(yàn)證;
- 測(cè)試時(shí)用具體的邊界日期驗(yàn)證:比如
CURDATE()替換為'2026-03-23'(周一)、'2026-03-29'(周日)。
5.4 坑四:不同MySQL版本的WEEK模式差異
MySQL的WEEK()函數(shù)有多種模式,但本文用的是WEEKDAY()和DAYOFWEEK(),這兩個(gè)函數(shù)在所有MySQL版本(5.7、8.0、8.4)中的定義都是一致的,沒(méi)有版本差異,可以放心使用。
六、總結(jié):周日期查詢速查表
為了方便大家直接復(fù)制使用,我們整理了周一為一周第一天的速查表:
| 需求 | SQL語(yǔ)句 |
|---|---|
| 獲取本周的周一 | 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) |
核心結(jié)論:
- 優(yōu)先明確周的定義(周一還是周日為第一天),國(guó)內(nèi)業(yè)務(wù)默認(rèn)用周一;
- 基于
WEEKDAY()函數(shù)的邏輯最直觀,且經(jīng)過(guò)多場(chǎng)景驗(yàn)證; - 查詢時(shí)間范圍時(shí),用
< 結(jié)束日期+1天避免遺漏時(shí)分秒; - 所有SQL都可以將
CURDATE()替換為任意日期字段,靈活適配業(yè)務(wù)。
以上就是MySQL周日期查詢之精準(zhǔn)獲取上周/本周的周一和周日全攻略的詳細(xì)內(nèi)容,更多關(guān)于MySQL日期查詢的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
從云數(shù)據(jù)遷移服務(wù)看MySQL大表抽取模式的原理解析
這篇文章主要介紹了從云數(shù)據(jù)遷移服務(wù)看MySQL大表抽取模式的原理解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
VS2019連接mysql8.0數(shù)據(jù)庫(kù)的教程圖文詳解
這篇文章主要介紹了VS2019連接mysql8.0數(shù)據(jù)庫(kù)的教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05
mysql中的utf8與utf8mb4存儲(chǔ)及區(qū)別
本文主要介紹了mysql中的utf8與utf8mb4存儲(chǔ)及區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
比較詳細(xì)的MySQL字段類(lèi)型說(shuō)明
MySQL支持大量的列類(lèi)型,它可以被分為3類(lèi):數(shù)字類(lèi)型、日期和時(shí)間類(lèi)型以及字符串(字符)類(lèi)型。本節(jié)首先給出可用類(lèi)型的一個(gè)概述,并且總結(jié)每個(gè)列類(lèi)型的存儲(chǔ)需求,然后提供每個(gè)類(lèi)中的類(lèi)型性質(zhì)的更詳細(xì)的描述。概述有意簡(jiǎn)化,更詳細(xì)的說(shuō)明應(yīng)該考慮到有關(guān)特定列類(lèi)型的附加信息,例如你能為其指定值的允許格式。2008-08-08
MySQL數(shù)據(jù)遷移相關(guān)總結(jié)
這篇文章主要介紹了MySQL數(shù)據(jù)遷移的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用MySQL數(shù)據(jù)庫(kù),感興趣的朋友可以了解下2021-04-04
MySQL按時(shí)間拆分千萬(wàn)級(jí)大表的實(shí)現(xiàn)代碼
這篇文章主要介紹了MySQL按時(shí)間拆分千萬(wàn)級(jí)大表,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09

