Saya melihat banyak orang menggunakan subqueries atau fitur khusus vendor untuk melakukan ini, tetapi saya sering melakukan query seperti ini tanpa subqueries dengan cara berikut. Ia menggunakan SQL standar yang sederhana sehingga harus bekerja di merek RDBMS apa pun.
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;
Dengan kata lain: ambil baris dari t1
tempat tidak ada baris lain yang samaUserId
dan lebih besar.
(Saya menempatkan pengidentifikasi "Tanggal" di pembatas karena itu kata yang dilindungi undang-undang.)
Dalam hal jika t1."Date" = t2."Date"
, penggandaan muncul. Biasanya tabel memiliki auto_inc(seq)
kunci, mis id
. Untuk menghindari penggandaan bisa digunakan berikut:
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;
Komentar ulang dari @ Farhan:
Berikut penjelasan yang lebih rinci:
Gabung luar mencoba bergabung t1
dengan t2
. Secara default, semua hasil t1
dikembalikan, dan jika ada kecocokan di t2
, itu juga dikembalikan. Jika tidak ada kecocokan t2
untuk satu baris tertentut1
, maka kueri masih mengembalikan baris t1
, dan digunakan NULL
sebagai pengganti untuk semuat2
kolom. Begitulah cara kerja gabungan luar secara umum.
Trik dalam kueri ini adalah merancang kondisi pencocokan gabungan sedemikian rupa sehingga t2
harus sama userid
, dan lebih besar date
. Gagasannya adalah jika ada baris t2
yang memiliki lebih besar date
, maka baris di t1
dalamnya dibandingkan dengan tidak bisa menjadi yang terbaik date
untuk itu userid
. Tetapi jika tidak ada kecocokan - yaitu jika tidak ada baris t2
dengan yang lebih besar date
dari pada baris t1
- kita tahu bahwa baris dalamt1
adalah baris dengan baris terbesar date
untuk yang diberikan userid
.
Dalam kasus tersebut (ketika tidak ada kecocokan), kolom t2
akan menjadi NULL
- bahkan kolom yang ditentukan dalam kondisi gabungan. Jadi itu sebabnya kami menggunakan WHERE t2.UserId IS NULL
, karena kami sedang mencari kasus di mana tidak ada baris ditemukan dengan yang lebih besar date
untuk yang diberikan userid
.