Để 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 độ
(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.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.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ểu | Khó | Dễ |
| Trường hợp không có ngày tương lai | Trả về ngày quá khứ gần nhất | Trả 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).