Saya memiliki tabel ("lms_attendance") waktu masuk dan keluar pengguna yang terlihat seperti ini:
id user time io (enum)
1 9 1370931202 out
2 9 1370931664 out
3 6 1370932128 out
4 12 1370932128 out
5 12 1370933037 in
Saya mencoba membuat tampilan tabel ini yang hanya akan menampilkan rekaman terbaru per id pengguna, sambil memberi saya nilai "masuk" atau "keluar", jadi seperti ini:
id user time io
2 9 1370931664 out
3 6 1370932128 out
5 12 1370933037 in
Sejauh ini saya cukup dekat, tetapi saya menyadari bahwa penayangan tidak akan menerima subquerys, yang membuatnya jauh lebih sulit. Pertanyaan terdekat yang saya dapatkan adalah:
select
`lms_attendance`.`id` AS `id`,
`lms_attendance`.`user` AS `user`,
max(`lms_attendance`.`time`) AS `time`,
`lms_attendance`.`io` AS `io`
from `lms_attendance`
group by
`lms_attendance`.`user`,
`lms_attendance`.`io`
Tapi yang saya dapatkan adalah:
id user time io
3 6 1370932128 out
1 9 1370931664 out
5 12 1370933037 in
4 12 1370932128 out
Yang mendekati, tapi tidak sempurna. Saya tahu bahwa grup terakhir seharusnya tidak ada di sana, tetapi tanpanya, grup ini mengembalikan waktu terakhir, tetapi tidak dengan nilai IO relatifnya.
Ada ide? Terima kasih!
mysql
sql
greatest-n-per-group
Keith
sumber
sumber
Jawaban:
Pertanyaan:
SQLFIDDLEExample
Hasil:
Solusi yang akan bekerja setiap saat:
SQLFIDDLEExample
sumber
Tidak perlu mencoba menemukan kembali roda, karena ini biasa terjadi terbesar per grup . Solusi yang sangat bagus disajikan .
Saya lebih suka solusi yang paling sederhana ( lihat SQLFiddle, memperbarui Justin ) tanpa subkueri (sehingga mudah digunakan dalam tampilan):
Ini juga berfungsi dalam kasus di mana ada dua rekaman berbeda dengan nilai terbesar yang sama dalam grup yang sama - berkat trik dengan
(t1.time = t2.time AND t1.Id < t2.Id)
. Semua yang saya lakukan di sini adalah untuk memastikan bahwa jika dua rekaman dari pengguna yang sama memiliki waktu yang sama, hanya satu yang dipilih. Tidak masalah jika kriteria ituId
atau sesuatu yang lain - pada dasarnya kriteria apa pun yang dijamin unik akan membuat pekerjaan di sini.sumber
t1.time < t2.time
dan jumlah minimumt1.time > t2.time
adalah kebalikan dari intuisi awal saya.t1.time < t2.time
kondisi berlaku :-)WHERE t2.user IS NULL
agak aneh. Peran apa yang dimainkan baris ini?OR (t1.time = t2.time AND t1.Id < t2.Id))
bagian?Berdasarkan jawaban @TMS, saya suka karena tidak perlu subkueri tetapi menurut saya menghilangkan
'OR'
bagian itu sudah cukup dan lebih sederhana untuk dipahami dan dibaca.jika Anda tidak tertarik dengan baris dengan waktu nol, Anda dapat memfilternya di
WHERE
klausa:sumber
OR
bagian tersebut adalah ide yang sangat buruk jika dua rekaman dapat memiliki kesamaantime
.Sudah terpecahkan, tetapi hanya sebagai catatan, pendekatan lain adalah membuat dua tampilan ...
Klik di sini untuk melihatnya beraksi di SQL Fiddle
sumber
sumber
join (select * from lms_attendance ) b
=join lms_attendance b
sumber
Jika Anda menggunakan MySQL 8.0 atau lebih tinggi, Anda dapat menggunakan fungsi Window :
Pertanyaan:
DBFiddleExample
Hasil:
Keuntungan yang saya lihat dibandingkan menggunakan solusi yang diusulkan oleh Justin adalah memungkinkan Anda memilih baris dengan data terbaru per pengguna (atau per id, atau per apa pun) bahkan dari subkueri tanpa memerlukan tampilan atau tabel perantara.
Dan jika Anda menjalankan HANA, ini juga ~ 7 kali lebih cepat: D
sumber
Oke, ini mungkin hack atau rawan kesalahan, tetapi entah bagaimana ini berfungsi juga-
sumber
Coba kueri ini:
sumber
id
danio
merupakan kolom nonagregasi, yang tidak dapat digunakan dalam filegroup by
.Mungkin Anda dapat melakukan kelompok berdasarkan pengguna dan kemudian memesan berdasarkan waktu desc. Sesuatu seperti di bawah ini
sumber
Ini berhasil untuk saya:
sumber