Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> MySQL

Tìm ngày gần nhất trong tương lai so với hiện tại trong MySQL

Để tìm bản ghi có ngày (shipping date, appointment, event) gần nhất trong tương lai so với thời điểm hiện tại, MySQL có thể dùng kỹ thuật sắp xếp đặc biệt: ưu tiên các ngày > NOW(), sau đó sắp xếp tăng dần trong nhóm đó.

Ví dụ minh họa

Tạo bảng ngày giao hàng:

mysql> CREATE TABLE DemoTable1454 (
    ShippingDate DATE
);

Chèn dữ liệu (có ngày quá khứ và tương lai):

mysql> INSERT INTO DemoTable1454 VALUES ('2019-10-01');
mysql> INSERT INTO DemoTable1454 VALUES ('2019-10-03');
mysql> INSERT INTO DemoTable1454 VALUES ('2019-10-05');
mysql> INSERT INTO DemoTable1454 VALUES ('2019-10-04');
mysql> INSERT INTO DemoTable1454 VALUES ('2018-10-06');
mysql> INSERT INTO DemoTable1454 VALUES ('2019-10-06');

Dữ liệu:

mysql> SELECT * FROM DemoTable1454;
+--------------+
| ShippingDate |
+--------------+
| 2019-10-01   |
| 2019-10-03   |
| 2019-10-05   |
| 2019-10-04   |
| 2018-10-06   |
| 2019-10-06   |
+--------------+

Thời điểm hiện tại:

mysql> SELECT NOW();
+---------------------+
| now()               |
+---------------------+
| 2019-10-04 21:30:01 |
+---------------------+

Truy vấn tìm ngày giao hàng tiếp theo (gần nhất trong tương lai)

mysql> SELECT * FROM DemoTable1454
    ORDER BY (ShippingDate > NOW()) DESC,
             CASE WHEN ShippingDate > NOW() THEN ShippingDate END,
             ShippingDate DESC
    LIMIT 1;

Kết quả (ngày 2019-10-05 — ngày sau hôm nay):

+--------------+
| ShippingDate |
+--------------+
| 2019-10-05   |
+--------------+

Giải thích logic ORDER BY 3 cấp độ

  1. (ShippingDate > NOW()) DESC: Biểu thức boolean TRUE (1) > FALSE (0). Sắp DESC → các ngày lớn hơn NOW() (tương lai) lên đầu.
  2. CASE WHEN ShippingDate > NOW() THEN ShippingDate END: Trong nhóm tương lai, sắp xếp tăng dần (ASC mặc định) → ngày gần nhất lên đầu. Các hàng quá khứ có giá trị NULL → rơi xuống cuối.
  3. ShippingDate DESC: Tie-breaker cho nhóm quá khứ (nếu không có ngày tương lai).

Cách viết đơn giản hơn (MySQL 8.0+ / chuẩn SQL)

-- Chỉ lấy ngày >= hôm nay, sắp tăng, lấy 1
SELECT * FROM DemoTable1454
WHERE ShippingDate >= CURDATE()
ORDER BY ShippingDate ASC
LIMIT 1;

Cách này tốt hơn hẳn: tận dụng index trên ShippingDate, logic rõ ràng, hiệu năng cao.

So sánh 2 cách

Tiêu chíORDER BY phức tạp (không WHERE)WHERE + ORDER BY đơn giản
Dùng index❌ Không (biểu thức trên cột)✅ Có (range scan trên index)
Đọc hiểuKhóDễ
Trường hợp không có ngày tương laiTrả về ngày quá khứ gần nhấtTrả về rỗng (cần xử lý riêng)

Khuyến nghị: Dùng cách WHERE ... ORDER BY ... LIMIT 1 cho production. Cách ORDER BY phức tạp chỉ dành cho bài toán học thuật hoặc yêu cầu đặc biệt (phải trả về 1 hàng dù không có ngày tương lai).