Saya ingin dapat memilih sekelompok baris dari tabel email dan mengelompokkannya berdasarkan pengirim dari. Kueri saya terlihat seperti ini:
SELECT
`timestamp`, `fromEmail`, `subject`
FROM `incomingEmails`
GROUP BY LOWER(`fromEmail`)
ORDER BY `timestamp` DESC
Kueri hampir berfungsi seperti yang saya inginkan - ini memilih catatan yang dikelompokkan berdasarkan email. Masalahnya adalah subjek dan stempel waktu tidak sesuai dengan catatan terbaru untuk alamat email tertentu.
Misalnya, mungkin mengembalikan:
fromEmail: john@example.com, subject: hello
fromEmail: mark@example.com, subject: welcome
Ketika catatan dalam database adalah:
fromEmail: john@example.com, subject: hello
fromEmail: john@example.com, subject: programming question
fromEmail: mark@example.com, subject: welcome
Jika subjek "pertanyaan pemrograman" adalah yang terbaru, bagaimana saya bisa meminta MySQL untuk memilih rekaman itu saat mengelompokkan email?
sumber
As of 5.7.5 ONLY_FULL_GROUP_BY is enabled by default, i.e. it's impossible to use non-aggregate columns.
Mode SQL dapat diubah selama runtime tanpa hak admin, jadi sangat mudah untuk menonaktifkan ONLY_FULL_GROUP_BY. Sebagai contoh:SET SESSION sql_mode = '';
. Demo: db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/3Inilah satu pendekatan:
Pada dasarnya, Anda bergabung dengan tabel itu sendiri, mencari baris selanjutnya. Di klausa where Anda menyatakan bahwa tidak dapat ada baris selanjutnya. Ini hanya memberi Anda baris terbaru.
Jika ada beberapa email dengan stempel waktu yang sama, kueri ini perlu diperbaiki. Jika ada kolom ID tambahan di tabel email, ubah JOIN seperti:
sumber
textID
itu ambigu = /LEFT JOIN
kriteriaAND next.timestamp <= UNIX_TIMESTAMP()
Seperti yang sudah ditunjukkan dalam balasan, jawaban saat ini salah, karena GROUP BY secara sewenang-wenang memilih rekaman dari jendela.
Jika seseorang menggunakan MySQL 5.6, atau MySQL 5.7 dengan
ONLY_FULL_GROUP_BY
, kueri yang benar (deterministik) adalah:Agar kueri dapat berjalan secara efisien, diperlukan pengindeksan yang tepat.
Perhatikan bahwa untuk tujuan penyederhanaan, saya telah menghapus
LOWER()
, yang dalam banyak kasus, tidak akan digunakan.sumber
order by
subpilihan di jawaban lain, tidak berpengaruh sama sekali.Lakukan GROUP BY setelah ORDER BY dengan membungkus kueri Anda dengan GROUP BY seperti ini:
sumber
time
, atau terbarutime
, atau acak?time DESC
dan kemudian grup dengan mengambil yang pertama (terbaru).Menurut standar SQL Anda tidak dapat menggunakan kolom non-agregat dalam daftar pilih. MySQL mengizinkan penggunaan seperti itu (mode ONLY_FULL_GROUP_BY digunakan) tetapi hasilnya tidak dapat diprediksi.
ONLY_FULL_GROUP_BY
Anda harus terlebih dahulu memilih fromEmail, MIN (read), dan kemudian, dengan kueri kedua (atau subkueri) - Subjek.
sumber
Saya berjuang dengan kedua pendekatan ini untuk kueri yang lebih kompleks daripada yang ditampilkan, karena pendekatan subkueri sangat tidak efisien tidak peduli indeks apa yang saya gunakan, dan karena saya tidak bisa mendapatkan penggabungan mandiri luar melalui Hibernate.
Cara terbaik (dan termudah) untuk melakukan ini adalah dengan mengelompokkan berdasarkan sesuatu yang dibangun untuk memuat rangkaian bidang yang Anda perlukan dan kemudian menariknya keluar menggunakan ekspresi dalam klausa SELECT. Jika Anda perlu melakukan MAX () pastikan bahwa bidang yang ingin Anda MAX () lewati selalu di ujung paling signifikan dari entitas gabungan.
Kunci untuk memahami hal ini adalah bahwa kueri hanya bisa masuk akal jika bidang lain ini invarian untuk setiap entitas yang memenuhi Max (), jadi dalam hal pengurutan, bagian lain dari penggabungan dapat diabaikan. Ini menjelaskan bagaimana melakukan ini di bagian paling bawah tautan ini. http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html
Jika Anda bisa mendapatkan acara sisipkan / perbarui (seperti pemicu) untuk menghitung sebelumnya rangkaian bidang, Anda dapat mengindeksnya dan kueri akan secepat jika grup tersebut berada di atas bidang yang sebenarnya Anda inginkan untuk MAX ( ). Anda bahkan dapat menggunakannya untuk mendapatkan beberapa bidang secara maksimal. Saya menggunakannya untuk melakukan kueri terhadap pohon multi-dimensi yang diekspresikan sebagai kumpulan bersarang.
sumber