Dengan tabel MySQL berikut ini:
+-----------------------------+
+ id INT UNSIGNED +
+ name VARCHAR(100) +
+-----------------------------+
Bagaimana cara memilih satu baris DAN posisinya di antara baris lain dalam tabel, jika diurutkan berdasarkan name ASC
. Jadi jika tabel datanya terlihat seperti ini, bila diurutkan berdasarkan nama:
+-----------------------------+
+ id | name +
+-----------------------------+
+ 5 | Alpha +
+ 7 | Beta +
+ 3 | Delta +
+ ..... +
+ 1 | Zed +
+-----------------------------+
Bagaimana saya bisa memilih Beta
baris yang mendapatkan posisi saat ini dari baris itu? Kumpulan hasil yang saya cari akan menjadi seperti ini:
+-----------------------------+
+ id | position | name +
+-----------------------------+
+ 7 | 2 | Beta +
+-----------------------------+
Saya dapat melakukan yang sederhana SELECT * FROM tbl ORDER BY name ASC
lalu menghitung baris dalam PHP, tetapi tampaknya sia-sia untuk memuat kumpulan hasil yang berpotensi besar hanya untuk satu baris.
sql
mysql
analytic-functions
leepowers
sumber
sumber
Jawaban:
Gunakan ini:
SELECT x.id, x.position, x.name FROM (SELECT t.id, t.name, @rownum := @rownum + 1 AS position FROM TABLE t JOIN (SELECT @rownum := 0) r ORDER BY t.name) x WHERE x.name = 'Beta'
... untuk mendapatkan nilai posisi yang unik. Ini:
SELECT t.id, (SELECT COUNT(*) FROM TABLE x WHERE x.name <= t.name) AS position, t.name FROM TABLE t WHERE t.name = 'Beta'
... akan memberikan nilai yang sama pada ikatan. YAITU: Jika ada dua nilai di tempat kedua, keduanya akan memiliki posisi 2 ketika kueri pertama akan memberikan posisi 2 ke salah satunya, dan 3 ke yang lain ...
sumber
position
, tapi sempurna.Inilah satu-satunya cara yang dapat saya pikirkan:
SELECT `id`, (SELECT COUNT(*) FROM `table` WHERE `name` <= 'Beta') AS `position`, `name` FROM `table` WHERE `name` = 'Beta'
sumber
name <= 'Beta'
bukannyaposition
untuk ikatan.LIMIT 1
di sana? Jika terjadi seri, Anda hanya akan mendapatkan satu baris dengan posisi terakhir seri.name
bidang itu unik - maka tidak ada alasan untuk membuat kueri lebih kompleks. Jika dia tidak bisa - maka mari kita tunggu ekspektasi hasilnya untuk nama seri.Jika kueri sederhana dan ukuran kumpulan hasil yang dikembalikan berpotensi besar, Anda dapat mencoba membaginya menjadi dua kueri.
Kueri pertama dengan kriteria pemfilteran yang dipersempit hanya untuk mengambil data dari baris itu, dan kueri kedua menggunakan klausa
COUNT
withWHERE
untuk menghitung posisi.Misalnya dalam kasus Anda
Pertanyaan 1:
SELECT * FROM tbl WHERE name = 'Beta'
Pertanyaan 2:
SELECT COUNT(1) FROM tbl WHERE name >= 'Beta'
Kami menggunakan pendekatan ini dalam tabel dengan catatan 2M dan ini jauh lebih skalabel daripada pendekatan OMG Pony.
sumber
Jawaban lain sepertinya terlalu rumit bagi saya.
Inilah contoh mudahnya , katakanlah Anda memiliki tabel dengan kolom:
dan Anda ingin mengurutkan userid berdasarkan poin dan mendapatkan posisi baris ("peringkat" pengguna), lalu Anda menggunakan:
SET @row_number = 0; SELECT (@row_number:=@row_number + 1) AS num, userid, points FROM ourtable ORDER BY points DESC
num
memberi Anda posisi baris (peringkat).Jika Anda memiliki MySQL 8.0+, Anda mungkin ingin menggunakan ROW_NUMBER ()
sumber
Posisi baris dalam tabel menunjukkan berapa banyak baris yang "lebih baik" dari baris yang ditargetkan.
Jadi, Anda harus menghitung baris-baris itu.
PILIH COUNT (*) + 1 DARI
table
MANAname
<'Beta'Jika terjadi seri, posisi tertinggi dikembalikan.
Jika Anda menambahkan baris lain dengan nama yang sama dari "Beta" setelah baris "Beta" yang ada, maka posisi yang dikembalikan akan tetap 2, karena mereka akan berbagi tempat yang sama dalam klasifikasi.
Semoga ini membantu orang-orang yang akan mencari sesuatu yang serupa di masa depan, karena saya yakin pemilik pertanyaan sudah memecahkan masalahnya.
sumber
Saya memiliki masalah yang sangat mirip, itulah mengapa saya tidak akan mengajukan pertanyaan yang sama, tetapi saya akan berbagi di sini apa yang telah saya lakukan, saya juga harus menggunakan grup oleh, dan memesan oleh AVG. Ada siswa, dengan tanda tangan dan socore, dan saya harus memeringkat mereka (dengan kata lain, saya menghitung AVG terlebih dahulu, lalu memesannya di DESC, dan akhirnya saya perlu menambahkan posisi (peringkat untuk saya), jadi saya lakukan sesuatu yang sangat mirip sebagai jawaban terbaik sini, dengan sedikit perubahan yang menyesuaikan dengan masalah saya):
Saya akhirnya menempatkan kolom
position
(peringkat untuk saya) di PILIHAN eksternalSET @rank=0; SELECT @rank := @rank + 1 AS ranking, t.avg, t.name FROM(SELECT avg(students_signatures.score) as avg, students.name as name FROM alumnos_materia JOIN (SELECT @rownum := 0) r left JOIN students ON students.id=students_signatures.id_student GROUP BY students.name order by avg DESC) t
sumber
Saya telah melalui jawaban yang diterima dan tampaknya agak rumit jadi inilah versi yang disederhanakan.
SELECT t,COUNT(*) AS position FROM t WHERE name <= 'search string' ORDER BY name
sumber
Saya memiliki jenis masalah yang serupa di mana saya memerlukan peringkat ( Indeks ) tabel
order by votes desc
. Berikut ini bekerja dengan baik untuk saya.Select *, ROW_NUMBER() OVER(ORDER BY votes DESC) as "rank" From "category_model" where ("model_type" = ? and "category_id" = ?)
sumber
Mungkin yang Anda butuhkan adalah dengan menambahkan sintaks
jadi gunakan
SELECT * FROM tbl ORDER BY name ASC LIMIT 1
jika Anda hanya perlu satu baris ..
sumber