MySQL - Dapatkan nomor baris pada pilih

181

Bisakah saya menjalankan pernyataan pilih dan mendapatkan nomor baris jika item diurutkan?

Saya punya tabel seperti ini:

mysql> describe orders;
+-------------+---------------------+------+-----+---------+----------------+
| Field       | Type                | Null | Key | Default | Extra          |
+-------------+---------------------+------+-----+---------+----------------+
| orderID     | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| itemID      | bigint(20) unsigned | NO   |     | NULL    |                |
+-------------+---------------------+------+-----+---------+----------------+

Saya kemudian dapat menjalankan kueri ini untuk mendapatkan jumlah pesanan berdasarkan ID:

SELECT itemID, COUNT(*) as ordercount
FROM orders
GROUP BY itemID ORDER BY ordercount DESC;

Ini memberi saya hitungan masing-masing itemIDdalam tabel seperti ini:

+--------+------------+
| itemID | ordercount |
+--------+------------+
|    388 |          3 |
|    234 |          2 |
|   3432 |          1 |
|    693 |          1 |
|   3459 |          1 |
+--------+------------+

Saya ingin mendapatkan nomor baris juga, jadi saya bisa tahu itu itemID=388adalah baris pertama, 234kedua, dll (pada dasarnya peringkat pesanan, bukan hanya hitungan mentah). Saya tahu saya bisa melakukan ini di Jawa ketika saya mendapatkan hasil yang ditetapkan kembali, tapi saya bertanya-tanya apakah ada cara untuk menanganinya murni di SQL.

Memperbarui

Mengatur peringkat menambahkannya ke set hasil, tetapi tidak dipesan dengan benar:

mysql> SET @rank=0;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
    -> FROM orders
    -> GROUP BY itemID ORDER BY rank DESC;
+------+--------+------------+
| rank | itemID | ordercount |
+------+--------+------------+
|    5 |   3459 |          1 |
|    4 |    234 |          2 |
|    3 |    693 |          1 |
|    2 |   3432 |          1 |
|    1 |    388 |          3 |
+------+--------+------------+
5 rows in set (0.00 sec)
George
sumber
1
Untuk referensi di masa mendatang: Jika Anda ingin memesan dari peringkat 1 ke peringkat 5, gunakan ORDER BY rank ASC(memesan berdasarkan peringkat dalam urutan ASCending). Saya kira itulah yang Anda maksudkan tetapi tidak dipesan dengan benar
BlueCacti
Kemungkinan duplikat ROW_NUMBER () di MySQL
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

180

Lihatlah ini .

Ubah kueri Anda menjadi:

SET @rank=0;
SELECT @rank:=@rank+1 AS rank, itemID, COUNT(*) as ordercount
  FROM orders
  GROUP BY itemID
  ORDER BY ordercount DESC;
SELECT @rank;

Pilihan terakhir adalah hitungan Anda.

Mike Cialowicz
sumber
1
Itu menambah pangkat pada set hasil, tetapi tidak menempatkan mereka dalam urutan yang tepat - pertanyaan yang diperbarui dengan hasil
George
1
Coba simpan ORDER BY ordercount DESC, dan kemudian bungkus seluruh kueri di yang lain SELECTyang mendapatkan semuanya dari yang pertama, tetapi pesan berdasarkan kolom peringkat (0 dalam kasus ini).
Mike Cialowicz
1
Bisakah Anda menunjukkan contohnya? Bagaimana saya membungkus pilihan?
George
9
Lihatlah jawaban swamibebop
thaddeusmt
1
@ MikeCialowicz, Ini tidak berfungsi . Lihat solusi saya atau solusi Swamibebop untuk jawaban yang tepat.
Pacerier
178
SELECT @rn:=@rn+1 AS rank, itemID, ordercount
FROM (
  SELECT itemID, COUNT(*) AS ordercount
  FROM orders
  GROUP BY itemID
  ORDER BY ordercount DESC
) t1, (SELECT @rn:=0) t2;
swamibebop
sumber
1
Terima kasih telah mengklarifikasi, ini memecahkan masalah rusak yang saya alami.
thaddeusmt
1
Terima kasih, ini benar-benar berguna bagi saya :) Saya terkejut tidak ada cara yang lebih mudah untuk mendapatkan 'indeks' baris dari hasil yang ditetapkan ... tetapi bagaimanapun juga terima kasih ini berguna.
tikus
Anda dapat menambahkan baris keempat dengan jumlah total tambahan dengan mengubah pernyataan pilih pertama dalam SELECT \ @rn: = \ @ rn + 1 AS rank, itemID, ordercount, \ @tot: = \ @ tot + ordercount sebagai totalcount. Untuk menentukan nilai awal \ @tot ini harus ditambahkan setelah t2: (SELECT \ @tot: = 0) t3. Hapus \ sebelum setiap \ @, yang harus saya gunakan untuk menghindari format mini-Markdown.
Jan Ehrhardt
2
Adakah yang bisa menjelaskan relevansi t1dan t2?
Jared
2
@ Jared, sintaks MySQL hanya perlu ada sesuatu di sana. Itu bisa apa saja, bahkan xdan y.
Pacerier
31

Solusi Swamibebop bekerja, tetapi dengan memanfaatkan table.*sintaksis, kita dapat menghindari pengulangan nama kolom dari bagian dalam selectdan mendapatkan hasil yang lebih sederhana / lebih pendek:

SELECT @r := @r+1 , 
       z.* 
FROM(/* your original select statement goes in here */)z, 
(SELECT @r:=0)y;

Jadi itu akan memberi Anda:

SELECT @r := @r+1 , 
       z.* 
FROM(
     SELECT itemID, 
     count(*) AS ordercount
     FROM orders
     GROUP BY itemID
     ORDER BY ordercount DESC
    )z,
    (SELECT @r:=0)y;
Pacerier
sumber
Apakah Anda kebetulan tahu mengapa menggunakan @r := @r + 1dalam pernyataan pilih berfungsi, tetapi jika itu dalam prosedur tersimpan dengan declare r int; set r = 0;, itu mengeluh (aktif r := r +1)?
Dan M.
@Pacerier, apakah urutan baris yang kedua dijamin di suatu tempat? Saya tahu bahwa urutan baris yang dikembalikan oleh pilih tanpa urutan oleh klausa tidak dijamin di mana pun, dan pilih terluar adalah persis seperti itu, meskipun itu dipilih dari pilihan dalam yang dipesan, jadi itu mungkin pengecualian. Namun, jika tidak, saya tidak dapat melihat bagaimana ini adalah solusi yang tepat karena ini akan memiliki kelemahan yang sama dengan Chibu's Mike - tidak ada jaminan di mana urutan pilih akan melalui catatan dan nomor mereka.
Dan M.
Apakah Anda tahu mengapa ORDER BY tidak berfungsi setiap kali tidak ada dalam daftar bidang? Lihat hasil saya: hastebin.com/aluqefunoy.rb
Musim Dingin
11

Anda dapat menggunakan variabel MySQL untuk melakukannya. Sesuatu seperti ini seharusnya bekerja (walaupun, itu terdiri dari dua pertanyaan).

SELECT 0 INTO @x;

SELECT itemID, 
       COUNT(*) AS ordercount, 
       (@x:=@x+1) AS rownumber 
FROM orders 
GROUP BY itemID 
ORDER BY ordercount DESC; 
Chibu
sumber
2
Hati-hati, ini tidak akan berhasil karena order byterjadi setelah variabel @xtelah dievaluasi. Coba bereksperimen dengan memesan menggunakan kolom lain. Juga bereksperimen dengan keduanya descdan asc. Anda akan melihat bahwa berkali-kali mereka akan gagal dan satu-satunya saat itu berhasil, itu adalah keberuntungan murni karena urutan "pilih" asli Anda memiliki urutan yang sama dengan urutan order by. Lihat solusi saya dan / atau solusi Swamibebop.
Pacerier
@Pacerier Anda yakin tentang itu? Saya sudah lelah kueri yang sama dalam contoh yang berbeda (pada dasarnya pilih dari kolom angka, dan nomorkan sesuai pesanan mereka) sepertinya jika saya memesan dengan var / row num, ketika itu mengubah urutan baris yang dihasilkan, tetapi setiap angka memiliki jumlah baris yang sama. Tetapi jika saya memesan berdasarkan kolom nomor, maka ASC/ DESCakan mengubah urutan nomor-nomor itu diberi nomor (dari terkecil ke terbesar atau sebaliknya). Jadi sepertinya dalam kasus order byitu dievaluasi dulu.
Dan M.
1

Sekarang sudah ada di MySQL 8.0 dan MariaDB 10.2:

SELECT
  itemID, COUNT(*) as ordercount,
  ROW_NUMBER OVER (PARTITION BY itemID ORDER BY rank DESC) as rank
FROM orders
GROUP BY itemID ORDER BY rank DESC
karam
sumber