Pertanyaan berikut:
SELECT
year, id, rate
FROM h
WHERE year BETWEEN 2000 AND 2009
AND id IN (SELECT rid FROM table2)
GROUP BY id, year
ORDER BY id, rate DESC
hasil:
year id rate
2006 p01 8
2003 p01 7.4
2008 p01 6.8
2001 p01 5.9
2007 p01 5.3
2009 p01 4.4
2002 p01 3.9
2004 p01 3.5
2005 p01 2.1
2000 p01 0.8
2001 p02 12.5
2004 p02 12.4
2002 p02 12.2
2003 p02 10.3
2000 p02 8.7
2006 p02 4.6
2007 p02 3.3
Yang saya inginkan hanya 5 hasil teratas untuk setiap id:
2006 p01 8
2003 p01 7.4
2008 p01 6.8
2001 p01 5.9
2007 p01 5.3
2001 p02 12.5
2004 p02 12.4
2002 p02 12.2
2003 p02 10.3
2000 p02 8.7
Apakah ada cara untuk melakukan ini menggunakan semacam LIMIT seperti pengubah yang berfungsi dalam GROUP BY?
LIMIT
klausa. Berikut ini adalah artikel yang menjelaskan masalah secara terperinci: Cara memilih baris pertama / paling sedikit / maksimum per grup dalam SQL Ini adalah artikel yang bagus - ia memperkenalkan solusi elegan namun naif untuk masalah "Top N per grup", dan kemudian secara bertahap memperbaikinya.Jawaban:
Anda dapat menggunakan fungsi agregat GROUP_CONCAT untuk mendapatkan semua tahun ke dalam satu kolom, dikelompokkan berdasarkan
id
dan dipesan olehrate
:Hasil:
Dan kemudian Anda bisa menggunakan FIND_IN_SET , yang mengembalikan posisi argumen pertama di dalam argumen kedua, misalnya.
Menggunakan kombinasi
GROUP_CONCAT
danFIND_IN_SET
, dan pemfilteran oleh posisi yang dikembalikan oleh find_in_set, Anda kemudian dapat menggunakan kueri ini yang hanya mengembalikan 5 tahun pertama untuk setiap id:Silakan lihat biola di sini .
Harap perhatikan bahwa jika lebih dari satu baris dapat memiliki tarif yang sama, Anda harus mempertimbangkan untuk menggunakan GROUP_CONCAT (HUBUNGI tarif ORDER BY rate) pada kolom tarif alih-alih kolom tahun.
Panjang maksimum string yang dikembalikan oleh GROUP_CONCAT terbatas, jadi ini berfungsi dengan baik jika Anda perlu memilih beberapa catatan untuk setiap grup.
sumber
SET SESSION group_concat_max_len = <maximum length>;
Dalam kasus OP, tidak ada masalah (karena standarnya adalah 1024), tetapi sebagai contoh, group_concat_max_len harus paling tidak 25: 4 (maks. panjang string tahun) + 1 (karakter pemisah), kali 5 (5 tahun pertama). String terpotong daripada melemparkan kesalahan, jadi perhatikan peringatan seperti1054 rows in set, 789 warnings (0.31 sec)
.FIND_IN_SET()
. Saya mencobaFIND_IN_SET() =2
tetapi tidak menunjukkan hasil seperti yang diharapkan.The query digunakan variabel pengguna dan
ORDER BY
pada tabel berasal; perilaku kedua kebiasaan tidak dijamin. Jawaban revisi sebagai berikut.Di MySQL 5.x Anda dapat menggunakan peringkat orang miskin di atas partisi untuk mencapai hasil yang diinginkan. Luar gabung dengan tabel dengan sendirinya dan untuk setiap baris, hitung jumlah baris lebih rendah dari itu. Dalam kasus di atas, baris yang lebih rendah adalah baris dengan tingkat yang lebih tinggi:
Demo dan Hasil :
Perhatikan bahwa jika tarif memiliki ikatan, misalnya:
Kueri di atas akan menghasilkan 6 baris:
Ubah untuk
HAVING COUNT(DISTINCT l.rate) < 5
mendapatkan 8 baris:Atau ubah untuk
ON t.id = l.id AND (t.rate < l.rate OR (t.rate = l.rate AND t.pri_key > l.pri_key))
mendapatkan 5 baris:Di MySQL 8 atau lebih baru cukup gunakan
RANK
,DENSE_RANK
atauROW_NUMBER
fungsi:sumber
WHERE rank <=5
? Untuk pertama kalinya saya tidak mendapatkan 5 baris dari setiap id, tetapi setelah itu saya bisa mendapatkan seperti yang Anda katakan.SET
pernyataan (lihat permintaan pertama). Itu perlu.ORDER BY
di dalam tabel turunan dapat, dan seringkali akan, diabaikan. Ini mengalahkan tujuan. Kelompok-bijaksana efisien ditemukan di sini .ORDER BY
di deliverd / subqueries seperti itu .. Itulah alasan mengapa versi modern MySQL / MariaDB mengabaikanORDER BY
subquery tanpa menggunakanLIMIT
, saya percaya ANSI / ISO SQL Standards 2008/2011/2016 membuatORDER BY
deliverd / subqueries legal ketika menggunakannya dalam kombinasi denganFETCH FIRST n ROWS ONLY
Bagi saya sesuatu seperti
bekerja dengan sempurna. Tidak ada permintaan yang rumit.
misalnya: dapatkan 1 teratas untuk setiap grup
sumber
Tidak, Anda tidak dapat LIMIT subqueries secara sewenang-wenang (Anda dapat melakukannya sampai batas tertentu di MySQL yang lebih baru, tetapi tidak untuk 5 hasil per grup).
Ini adalah tipe query groupwise-maksimum, yang tidak sepele untuk dilakukan dalam SQL. Ada berbagai cara untuk mengatasi hal yang lebih efisien untuk beberapa kasus, tetapi untuk top-n pada umumnya Anda akan ingin melihat jawaban Bill untuk pertanyaan sebelumnya yang serupa.
Seperti kebanyakan solusi untuk masalah ini, ini dapat mengembalikan lebih dari lima baris jika ada beberapa baris dengan nilai yang sama
rate
, jadi Anda mungkin masih memerlukan sejumlah pasca pemrosesan untuk memeriksanya.sumber
Ini membutuhkan serangkaian subquery untuk memeringkat nilai, membatasi mereka, lalu melakukan penjumlahan saat pengelompokan
sumber
Coba ini:
sumber
Subquery hampir identik dengan permintaan Anda. Hanya perubahan yang ditambahkan
sumber
ROW_NUMBER()
).row_number()
adalah tersedia .Buat kolom virtual (seperti RowID di Oracle)
meja:
data:
SQL seperti ini:
jika menghapus klausa where di t3, ini menunjukkan seperti ini:
DAPATKAN "TOP N Record" -> tambahkan "rownum <= 3" di mana klausa (di mana-klausa t3);
PILIH "tahun" -> tambahkan "BETWEEN 2000 AND 2009" di mana klausa (di mana-klausa t3);
sumber
Butuh beberapa kerja, tapi saya pikir solusi saya akan menjadi sesuatu untuk dibagikan karena tampaknya elegan dan juga cukup cepat.
Perhatikan bahwa contoh ini ditentukan untuk tujuan pertanyaan dan dapat dimodifikasi dengan mudah untuk tujuan serupa lainnya.
sumber
Posting berikut: sql: memilih top N record per grup menjelaskan cara rumit untuk mencapai ini tanpa subqueries.
Ini meningkatkan solusi lain yang ditawarkan di sini oleh:
Namun itu tidak cantik. Solusi yang baik akan dicapai adalah Fungsi Jendela (alias Fungsi Analitik) diaktifkan di MySQL - tetapi sebenarnya tidak. Trik yang digunakan dalam posting tersebut menggunakan GROUP_CONCAT, yang kadang-kadang digambarkan sebagai "Fungsi Jendela orang miskin untuk MySQL".
sumber
untuk orang-orang seperti saya yang punya waktu tunggu. Saya membuat di bawah ini untuk menggunakan batas dan apa pun oleh kelompok tertentu.
loop melalui daftar domain dan kemudian hanya menyisipkan batas masing-masing 200
sumber
Coba ini:
sumber
Silakan coba prosedur tersimpan di bawah ini. Saya sudah memverifikasi. Saya mendapatkan hasil yang tepat tetapi tanpa menggunakan
groupby
.sumber