Dengan MySQL, bagaimana saya bisa menghasilkan kolom yang berisi indeks catatan dalam tabel?


100

Apakah ada cara agar saya bisa mendapatkan nomor baris sebenarnya dari kueri?

Saya ingin dapat memesan tabel bernama league_girl dengan bidang yang disebut skor; dan mengembalikan nama pengguna dan posisi baris sebenarnya dari nama pengguna tersebut.

Saya ingin memberi peringkat pada pengguna sehingga saya dapat mengetahui di mana pengguna tertentu berada, yaitu. Joe berada di posisi 100 dari 200, yaitu

User Score Row
Joe  100    1
Bob  50     2
Bill 10     3

Saya telah melihat beberapa solusi di sini tetapi saya telah mencoba sebagian besar dari mereka dan tidak ada yang benar-benar mengembalikan nomor baris.

Saya sudah mencoba ini:

SELECT position, username, score
FROM (SELECT @row := @row + 1 AS position, username, score 
       FROM league_girl GROUP BY username ORDER BY score DESC) 

Seperti diturunkan

... tapi sepertinya tidak mengembalikan posisi baris.

Ada ide?


adalah baris nama file atau Anda ingin memesan dengan kunci utama?
Sarfraz

Dalam SQL, nomor baris sebenarnya tidak penting. Yang harus Anda lakukan adalah menambahkan kunci primer kenaikan otomatis ke tabel Anda.
simendsjo

9
Kunci utama TIDAK PERNAH menjadi pengenal baris karena tidak dapat diandalkan untuk posisi baris sebenarnya.
TheBounder

3
Selain itu, karena nomor baris akan menjadi fungsi dari skor yang saya anggap bukan nilai statis, menjadikannya nilai yang bertambah otomatis (kunci primer atau tidak) tidak akan memberikan hasil yang diinginkan.
kasperjj

Anda mungkin ingin menyimpan jelek untuk fungsi kustom, lihat datamakessense.com/mysql-rownum-row-number-function
AdrianBR

Jawaban:


174

Anda mungkin ingin mencoba yang berikut ini:

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r;

Bagian ini JOIN (SELECT @curRow := 0)memungkinkan inisialisasi variabel tanpa memerlukan SETperintah terpisah .

Kasus cobaan:

CREATE TABLE league_girl (position int, username varchar(10), score int);
INSERT INTO league_girl VALUES (1, 'a', 10);
INSERT INTO league_girl VALUES (2, 'b', 25);
INSERT INTO league_girl VALUES (3, 'c', 75);
INSERT INTO league_girl VALUES (4, 'd', 25);
INSERT INTO league_girl VALUES (5, 'e', 55);
INSERT INTO league_girl VALUES (6, 'f', 80);
INSERT INTO league_girl VALUES (7, 'g', 15);

Uji kueri:

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r
WHERE   l.score > 50;

Hasil:

+----------+----------+-------+------------+
| position | username | score | row_number |
+----------+----------+-------+------------+
|        3 | c        |    75 |          1 |
|        5 | e        |    55 |          2 |
|        6 | f        |    80 |          3 |
+----------+----------+-------+------------+
3 rows in set (0.00 sec)

19
Anda juga dapat menginisialisasi @curRowdengan mengganti JOINpernyataan dengan koma, seperti ini:FROM league_girl l, (SELECT @curRow := 0) r
Mike

2
@ Mike: Itu benar. Dan itu mungkin lebih rapi juga. Terima kasih telah membagikan tip ini.
Daniel Vassallo

2
@smhnaji MySQL mengharuskan setiap "tabel turunan" diberi nama. Saya memutuskan untuk menyebutnya "r" :) ... Dalam kasus ini, ini memiliki sedikit tujuan, tetapi Anda biasanya menggunakannya untuk mereferensikan atribut tabel turunan, seolah-olah itu adalah tabel nyata.
Daniel Vassallo

20
Orang-orang harus tahu bahwa nomor baris ini dihitung sebelum pengurutan dilakukan, jadi angkanya bisa campur aduk jika urutan mengubah urutan baris.
Suram ...

7
Apakah ada cara agar nomor baris ini dihitung setelah ORDER BY?
Pierre de LESPINAY

38
SELECT @i:=@i+1 AS iterator, t.*
FROM tablename t,(SELECT @i:=0) foo

apakah ada cara untuk melakukan ini sehingga kolom iterator adalah bilangan bulat dan bukan desimal?
kraftydevil

7

Inilah struktur template yang saya gunakan:

  select
          /*this is a row number counter*/
          ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
          as rownumber,
          d3.*
  from 
  ( select d1.* from table_name d1 ) d3

Dan inilah kode kerja saya:

select     
           ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
           as rownumber,
           d3.*
from
(   select     year( d1.date ), month( d1.date ), count( d1.id )
    from       maindatabase d1
    where      ( ( d1.date >= '2013-01-01' ) and ( d1.date <= '2014-12-31' ) )
    group by   YEAR( d1.date ), MONTH( d1.date ) ) d3

sempurna, karya seperti pesona dan template dapat digunakan kembali dengan subquery sebagai parameter ..
Zavael

Solusi ini juga berfungsi jika kueri dasar Anda menggunakan GROUP BY
Dave R

4

Anda juga bisa menggunakan

SELECT @curRow := ifnull(@curRow,0) + 1 Row, ...

untuk menginisialisasi variabel counter.


3
@curRowmungkin masih memiliki nilai dari terakhir kali Anda menjalankan kueri ini di sesi saat ini.
Bill Karwin

Benar, tetapi hanya jika Anda melakukan kueri ulang pada contoh koneksi yang sama. Variabel lokal secara otomatis dibuang setelah koneksi ditutup.
Pos Gizi

Ya, itulah yang saya maksud ketika saya mengatakan "dalam sesi saat ini."
Bill Karwin

3

Dengan asumsi MySQL mendukungnya, Anda dapat dengan mudah melakukan ini dengan subkueri SQL standar:

select 
    (count(*) from league_girl l1 where l2.score > l1.score and l1.id <> l2.id) as position,
    username,
    score
from league_girl l2
order by score;

Untuk hasil yang ditampilkan dalam jumlah besar, ini akan menjadi agak lambat dan Anda sebaiknya beralih ke self-join.


3

Jika Anda hanya ingin mengetahui posisi satu pengguna tertentu setelah memesan berdasarkan skor lapangan, Anda cukup memilih semua baris dari tabel Anda di mana skor lapangan lebih tinggi dari skor pengguna saat ini. Dan gunakan nomor baris yang dikembalikan + 1 untuk mengetahui posisi mana dari pengguna saat ini.

Dengan asumsi bahwa tabel Anda adalah league_girldan bidang utama Anda adalah id, Anda dapat menggunakan ini:

SELECT count(id) + 1 as rank from league_girl where score > <your_user_score>

0

Saya menemukan jawaban asli sangat membantu tetapi saya juga ingin mengambil serangkaian baris tertentu berdasarkan nomor baris yang saya masukkan. Karena itu, saya membungkus seluruh jawaban asli dalam subkueri sehingga saya bisa merujuk nomor baris yang saya sisipkan.

SELECT * FROM 
( 
    SELECT *, @curRow := @curRow + 1 AS "row_number"
    FROM db.tableName, (SELECT @curRow := 0) r
) as temp
WHERE temp.row_number BETWEEN 1 and 10;

Memiliki subkueri dalam subkueri tidak terlalu efisien, jadi sebaiknya Anda menguji apakah Anda mendapatkan hasil yang lebih baik dengan meminta server SQL Anda menangani kueri ini, atau mengambil seluruh tabel dan meminta aplikasi / server web memanipulasi baris setelah fakta. .

Secara pribadi server SQL saya tidak terlalu sibuk, jadi lebih baik jika menangani subkueri bersarang.


0

Saya tahu OP meminta mysqljawaban tetapi karena saya menemukan jawaban lain tidak berfungsi untuk saya,

  • Kebanyakan dari mereka gagal order by
  • Atau mereka sangat tidak efisien dan membuat kueri Anda sangat lambat untuk tabel gemuk

Jadi untuk menghemat waktu bagi orang lain seperti saya, cukup indeks baris setelah mengambilnya dari database

contoh di PHP:

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1;
}

contoh di PHP menggunakan offset dan limit untuk paging:

$limit = 20; //page size
$offset = 3; //page number

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1+($limit*($offset-1));
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.