Query อายุจาก DOB: หลายวิธีและข้อควรระวัง
วิธีที่ 1: ใช้ DATE_SUB / INTERVAL (ตัวอย่างในบทความ)
CREATE TABLE DemoTable611 (DOB DATE);
INSERT INTO DemoTable611 VALUES
('1996-04-21'), ('2001-01-31'), ('2004-12-21'), ('2000-02-03');
-- หาคนอายุ >= 16 ปี (DOB <= 16 ปีก่อน)
SELECT * FROM DemoTable611
WHERE DOB >= (CURDATE() - INTERVAL 16 YEAR);
หมายเหตุ: Query นี้หา "เกิดภายใน 16 ปีที่แล้ว" = อายุ < 16 ปี ไม่ใช่ >= 16 ปี
วิธีที่ถูกต้อง: คำนวณอายุจริง
-- อายุปัจจุบัน (ปี)
SELECT
DOB,
TIMESTAMPDIFF(YEAR, DOB, CURDATE()) AS age_years,
TIMESTAMPDIFF(MONTH, DOB, CURDATE()) AS age_months,
TIMESTAMPDIFF(DAY, DOB, CURDATE()) AS age_days
FROM DemoTable611;
TIMESTAMPDIFF(unit, start, end) คำนวณความต่างอย่างถูกต้อง (คำนึงถึงวันเกิดปีนี้ผ่านไปยัง)
วิธีเก่า: DATEDIFF + หาร 365.25 (ไม่แม่นยำ)
SELECT FLOOR(DATEDIFF(CURDATE(), DOB) / 365.25) AS approx_age
FROM DemoTable611;
❌ ไม่แม่นยำ เพราะ Leap Year และวันเกิดยังไม่ถึงในปีนี้
Query: หาคนอายุ 18-65 ปี (Working Age)
SELECT * FROM DemoTable611
WHERE TIMESTAMPDIFF(YEAR, DOB, CURDATE()) BETWEEN 18 AND 65;
ตัวอย่างเพิ่มเติม: อายุครบรอบวันเกิดปีนี้
SELECT
DOB,
CASE
WHEN DATE_FORMAT(DOB, '%m-%d') > DATE_FORMAT(CURDATE(), '%m-%d')
THEN YEAR(CURDATE()) - YEAR(DOB) - 1
ELSE YEAR(CURDATE()) - YEAR(DOB)
END AS age_exact
FROM DemoTable611;
สรุป Best Practice
- ใช้ TIMESTAMPDIFF(YEAR, DOB, CURDATE()) - ถูกต้อง เร็ว อ่านง่าย
- อย่าใช้ DATEDIFF/365.25 - ผิดพลาดได้
- ถ้าต้อง Query บ่อย ให้เพิ่ม Generated Column + Index:
ALTER TABLE users ADD COLUMN age_years INT GENERATED ALWAYS AS (TIMESTAMPDIFF(YEAR, dob, CURDATE())) STORED, ADD INDEX idx_age (age_years); - สำหรับ Birthday Reminder (วันเกิดใน 7 วันข้างหน้า):
SELECT * FROM users WHERE DATE_FORMAT(dob, '%m-%d') BETWEEN DATE_FORMAT(CURDATE(), '%m-%d') AND DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 7 DAY), '%m-%d');