Sử dụng subquery với MAX(UNIX_TIMESTAMP()) gom theo HOUR(), sau đó JOIN ngược lại bảng gốc để lấy toàn bộ cột của bản ghi mới nhất mỗi giờ.
Cú pháp
SELECT b.*
FROM (
SELECT MAX(UNIX_TIMESTAMP(cot_thoi_gian)) AS max_ts
FROM ten_bang
GROUP BY HOUR(cot_thoi_gian)
) AS t_max
JOIN ten_bang b ON UNIX_TIMESTAMP(b.cot_thoi_gian) = t_max.max_ts
WHERE DATE(b.cot_thoi_gian) = 'ngay_can_loc';
Ví dụ minh họa
Tạo bảng log đăng nhập:
mysql> CREATE TABLE LayGioGanNhat (
-> UserId INT,
-> UserName VARCHAR(20),
-> ThoiGianDangNhap DATETIME
-> );
Chèn dữ liệu (ngày 2019-02-04, nhiều giờ):
mysql> INSERT INTO LayGioGanNhat VALUES
-> (100, 'John', '2019-02-04 10:55:51'),
-> (101, 'Larry', '2019-02-04 12:30:40'),
-> (102, 'Carol', '2019-02-04 12:40:46'),
-> (103, 'David', '2019-02-04 12:44:54'),
-> (104, 'Bob', '2019-02-04 12:47:59');
Truy vấn: Bản ghi đăng nhập muộn nhất mỗi giờ
mysql> SELECT tbl1.*
-> FROM (
-> SELECT MAX(UNIX_TIMESTAMP(ThoiGianDangNhap)) AS m1
-> FROM LayGioGanNhat
-> GROUP BY HOUR(ThoiGianDangNhap)
-> ) var1
-> JOIN LayGioGanNhat tbl1 ON UNIX_TIMESTAMP(tbl1.ThoiGianDangNhap) = var1.m1
-> WHERE DATE(tbl1.ThoiGianDangNhap) = '2019-02-04';
Kết quả (giờ 10: John, giờ 12: Bob - muộn nhất):
+--------+----------+---------------------+ | UserId | UserName | ThoiGianDangNhap | +--------+----------+---------------------+ | 100 | John | 2019-02-04 10:55:51 | | 104 | Bob | 2019-02-04 12:47:59 | +--------+----------+---------------------+
Cách hiện đại (MySQL 8.0+): Dùng Window Function ROW_NUMBER():
WITH ranked AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY HOUR(ThoiGianDangNhap) ORDER BY ThoiGianDangNhap DESC) AS rn FROM LayGioGanNhat WHERE DATE(ThoiGianDangNhap) = '2019-02-04' ) SELECT * FROM ranked WHERE rn = 1;