Tôi thấy nhiều người sử dụng truy vấn con hoặc các hàm cửa sổ khác để thực hiện việc này, nhưng tôi thường thực hiện loại truy vấn này mà không cần truy vấn con theo cách sau. Nó sử dụng SQL chuẩn, đơn giản, vì vậy nó sẽ hoạt động trong bất kỳ thương hiệu RDBMS nào.
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON (t1.UserId = t2.UserId AND t1."Date" < t2."Date")
WHERE t2.UserId IS NULL;
Nói cách khác:tìm nạp hàng từ t1
trong đó không có hàng nào khác tồn tại với cùng một UserId
và một Ngày tuyệt vời hơn.
(Tôi đặt số nhận dạng "Ngày" trong dấu phân cách vì đó là từ dành riêng cho SQL.)
Trong trường hợp if t1."Date" = t2."Date"
, nhân đôi xuất hiện. Thông thường các bảng có auto_inc(seq)
chìa khóa, ví dụ:id
Để tránh nhân đôi có thể sử dụng như sau:
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON t1.UserId = t2.UserId AND ((t1."Date" < t2."Date")
OR (t1."Date" = t2."Date" AND t1.id < t2.id))
WHERE t2.UserId IS NULL;
Nhận xét lại từ @Farhan:
Đây là lời giải thích chi tiết hơn:
Một liên kết bên ngoài cố gắng tham gia t1
với t2
. Theo mặc định, tất cả kết quả của t1
được trả lại và nếu có sự trùng khớp trong t2
, nó cũng được trả lại. Nếu không có khớp nào trong t2
cho một hàng nhất định của t1
, sau đó truy vấn vẫn trả về hàng t1
và sử dụng NULL
làm trình giữ chỗ cho tất cả t2
của cột. Đó chỉ là cách các phép nối bên ngoài hoạt động nói chung.
Mẹo trong truy vấn này là thiết kế điều kiện kết hợp của phép nối sao cho t2
phải khớp với giống nhau userid
và một lớn hơn date
. Ý tưởng là nếu một hàng tồn tại trong t2
có date
lớn hơn , rồi đến hàng trong t1
nó được so sánh với không thể là date
vĩ đại nhất cho userid
đó . Nhưng nếu không có kết quả phù hợp - tức là nếu không có hàng nào tồn tại trong t2
với một date
lớn hơn hơn hàng trong t1
- chúng tôi biết rằng hàng trong t1
là hàng có date
lớn nhất cho userid
đã cho .
Trong những trường hợp đó (khi không có kết quả phù hợp), các cột của t2
sẽ là NULL
- ngay cả các cột được chỉ định trong điều kiện nối. Vì vậy, đó là lý do tại sao chúng tôi sử dụng WHERE t2.UserId IS NULL
, bởi vì chúng tôi đang tìm kiếm các trường hợp không tìm thấy hàng nào có date
lớn hơn cho userid
đã cho .