Bài toán
Gom nhóm theo UserName + UserEmailId, nhưng chỉ giữ bản ghi có UserLastPost mới nhất (MAX).
Ví dụ
Tạo bảng:
CREATE TABLE DemoTable621 (
UserName VARCHAR(100),
UserEmailId VARCHAR(100),
UserLastPost DATETIME
);
INSERT INTO DemoTable621 VALUES
('John', 'John@gmail.com', '2019-04-10 11:01:10'),
('John', 'John@gmail.com', '2019-07-14 13:07:10');
Truy vấn:
SELECT UserName, UserEmailId, MAX(UserLastPost)
FROM DemoTable621
GROUP BY UserName, UserEmailId;
Kết quả:
+----------+----------------+---------------------+
| UserName | UserEmailId | max(UserLastPost) |
+----------+----------------+---------------------+
| John | John@gmail.com | 2019-07-14 13:07:10 |
+----------+----------------+---------------------+
Mở rộng: Lấy toàn bộ cột của dòng MAX (Greatest-N-Per-Group)
Nếu cần lấy cả cột khác của dòng có MAX date:
Cách 1: JOIN với subquery (MySQL tất cả version)
SELECT d1.*
FROM DemoTable621 d1
JOIN (
SELECT UserName, UserEmailId, MAX(UserLastPost) AS max_post
FROM DemoTable621
GROUP BY UserName, UserEmailId
) d2 ON d1.UserName = d2.UserName
AND d1.UserEmailId = d2.UserEmailId
AND d1.UserLastPost = d2.max_post;
Cách 2: ROW_NUMBER() (MySQL 8.0+)
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY UserName, UserEmailId ORDER BY UserLastPost DESC) AS rn
FROM DemoTable621
) t
WHERE rn = 1;
Cách 3: Correlated subquery (chậm trên bảng lớn)
SELECT *
FROM DemoTable621 d1
WHERE UserLastPost = (
SELECT MAX(UserLastPost)
FROM DemoTable621 d2
WHERE d2.UserName = d1.UserName
AND d2.UserEmailId = d1.UserEmailId
);
Lưu ý
- MySQL cho phép SELECT cột không trong GROUP BY (non-aggregated) nhưng giá trị không xác định (chỉ bật ONLY_FULL_GROUP_BY mới báo lỗi).
- Luôn liệt kê rõ cột trong GROUP BY khớp với SELECT.
- Index trên (UserName, UserEmailId, UserLastPost) tối ưu cho query này.