首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 查詢 5 天內生日同事:跨年邊界條件的通用解法

     編輯:MySQL 綜合教學

MySQL 查詢 5 天內生日同事:跨年邊界條件的通用解法

業務常見需求:「查詢未來 N 天內過生日的同事」。核心難點在於**跨年邊界**:12 月底查詢時,1 月初的生日屬於「明年」,直接用今年年份構造日期會導致 DATEDIFF 為負數,查漏數據。本文給出通用雙分支解法並完整驗證。

問題分析

  • 生日列存 DATE(如 1992-01-01),無年份業務含義。
  • 查詢時需構造「今年生日日期」與「明年生日日期」,分別與今天比較天數差。
  • DATEDIFF(date1, date2) 返回 date1 - date2 天數,未來 N 天含今日 = BETWEEN 0 AND N-1。

通用 SQL 模板

SELECT * FROM ali_users WHERE
  -- 分支 1:今年生日在未來 5 天內(含今日)
  DATEDIFF(
    CAST(CONCAT(YEAR(NOW()), DATE_FORMAT(birthday, '-%m-%d')) AS DATE),
    CAST(DATE_FORMAT(NOW(), '%Y-%m-%d') AS DATE)
  ) BETWEEN 0 AND 4
  OR
  -- 分支 2:明年生日在未來 5 天內(解決跨年)
  DATEDIFF(
    CAST(CONCAT(YEAR(NOW())+1, DATE_FORMAT(birthday, '-%m-%d')) AS DATE),
    CAST(DATE_FORMAT(NOW(), '%Y-%m-%d') AS DATE)
  ) BETWEEN 0 AND 4;

關鍵函數解析

  • DATE_FORMAT(birthday, '-%m-%d'):提取月日,拼接為 -MM-DD。
  • CONCAT(YEAR(NOW()), ...):構造「今年生日完整日期」。
  • CAST(... AS DATE):字符串轉日期類型,供 DATEDIFF 使用。
  • YEAR(NOW())+1:構造「明年生日」,覆蓋 12 月底查 1 月初場景。

完整驗證過程

1. 準備測試數據(含跨年樣本)

CREATE TABLE ali_users (
  username VARCHAR(10), birthday DATE NOT NULL, iphone VARCHAR(16)
);
INSERT INTO ali_users VALUES
('MaoYi','1985-09-04','13998786543'), ('LiuEr','1985-08-30','13998786543'),
('ZhangSan','1981-01-01','13998786543'), ('LiSi','1983-01-02','13998786543'),
('WangWu','1984-11-01','13998786543'), ('ZhaoLiu','1984-11-01','13998786543'),
('SongQi','1986-08-31','13998786543'), ('HuangBa','1989-09-01','13998786543'),
('ZengJiu','1989-09-02','13998786543'), ('LuoShi','1985-09-03','13998786543'),
('Tom','1995-09-05','13998786543'), ('Licy','1991-12-30','13998286543'),
('Cari','1992-12-31','13998286543'), ('Mark','1992-01-03','13998286543'),
('Ruby','1992-01-04','13998286547');

2. 場景 A:非跨年(今日 8 月 30 日)

-- 直接用 NOW() 執行
-- 結果 5 條:LiuEr(8/30)、SongQi(8/31)、HuangBa(9/1)、ZengJiu(9/2)、LuoShi(9/3)
-- 驗證:8/30~9/3 共 5 天,正確

3. 場景 B:跨年(模擬今日 2013-12-30)

-- 應用層生成:['08-30','08-31','09-01','09-02','09-03']
SELECT * FROM ali_users 
WHERE DATE_FORMAT(birthday, '%m-%d') IN ('08-30','08-31','09-01','09-02','09-03');
  • 可命中 birthday 列索引(需建函數索引或冗余 birthday_md CHAR(5) 列)。
  • 避免資料庫端函數計算,性能提升數量級。

擴展:N 天參數化

SET @days = 5;  -- 可改為 7、30 等
SELECT * FROM ali_users WHERE
  DATEDIFF(CAST(CONCAT(YEAR(NOW()), DATE_FORMAT(birthday, '-%m-%d')) AS DATE), CAST(DATE_FORMAT(NOW(), '%Y-%m-%d') AS DATE)) BETWEEN 0 AND @days-1
  OR
  DATEDIFF(CAST(CONCAT(YEAR(NOW())+1, DATE_FORMAT(birthday, '-%m-%d')) AS DATE), CAST(DATE_FORMAT(NOW(), '%Y-%m-%d') AS DATE)) BETWEEN 0 AND @days-1;

總結

**「雙分支:今年 + 明年」是解決生日跨年查詢的通用模式**。核心在於構造兩個候選日期分別比較,邏輯清晰、兼容性強(MySQL 5.1+ 均可用)。大表生產環境建議**應用層預計算日期集合 + 索引優化**,將計算下推、避免全表掃描。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved