MySQL ile bir tablodaki kayıt indeksini içeren bir sütunu nasıl oluşturabilirim?


100

Bir sorgudan gerçek satır numarasını alabilmemin bir yolu var mı?

Score adlı bir alana göre league_girl adlı bir tablo sipariş edebilmek istiyorum; ve bu kullanıcı adının kullanıcı adını ve gerçek satır konumunu döndürün.

Kullanıcıları sıralamak istiyorum, böylece belirli bir kullanıcının nerede olduğunu söyleyebilirim, yani. Joe, 200 üzerinden 100. sırada, yani

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

Burada birkaç çözüm gördüm ama çoğunu denedim ve hiçbiri aslında satır numarasını döndürmüyor.

Bunu denedim:

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

Türetildiği gibi

... ancak sıra konumuna dönmüyor gibi görünüyor.

Herhangi bir fikir?


satır dosyalanmış bir ad mı yoksa birincil anahtara göre mi sıralamak istiyorsunuz?
Sarfraz

SQL'de satır numaraları gerçekten önemli değildir. Yapmanız gereken, tablonuza otomatik artışlı bir birincil anahtar eklemektir.
simendsjo

9
Birincil anahtar, gerçek satır konumu için güvenilir olmadıklarından ASLA bir satır tanımlayıcısı olmamalıdır.
TheBounder

3
Ayrıca, satır numarası, statik bir değer olmadığını düşündüğüm puanın bir fonksiyonu olacağından, onu otomatik olarak artırılmış bir değer (birincil anahtar veya değil) yapmak istenen sonucu vermeyecektir.
kasperjj

çirkin olanı
AdrianBR

Yanıtlar:


174

Aşağıdakileri denemek isteyebilirsiniz:

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

JOIN (SELECT @curRow := 0)Parçası, ayrı bir gerektirmeden değişken başlatma sağlar SETkomutu.

Test durumu:

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);

Test sorgusu:

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;

Sonuç:

+----------+----------+-------+------------+
| 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
İfadeyi virgülle @curRowdeğiştirerek de şu şekilde başlatabilirsiniz JOIN:FROM league_girl l, (SELECT @curRow := 0) r
Mike

2
@Mike: Bu doğru. Ve bu muhtemelen daha düzgün. Bu ipucunu paylaştığınız için teşekkürler.
Daniel Vassallo

2
@smhnaji MySQL, her "türetilmiş tabloya" bir ad verilmesini gerektirir. Ben buna "r" demeye karar verdim :) ... Bu durumda bunun pek bir amacı yoktur, ancak normalde onu türetilmiş tablonun özniteliklerine başvurmak için kullanırsınız, sanki gerçek bir tablodaymış gibi.
Daniel Vassallo

20
Kişiler, bu satır numarasının herhangi bir sıralama yapılmadan önce hesaplandığının farkında olmalıdır , bu nedenle sıra satır sırasını değiştirirse sayılar karışık olabilir.
Grim ...

7
Bu satır numarasını sonra hesaplamanın bir yolu var mı ORDER BY?
Pierre de LESPINAY

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

yineleyici sütunun ondalık değil tam sayı olması için bunu yapmanın bir yolu var mı?
kraftydevil

7

İşte kullandığım şablonun yapısı:

  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

Ve işte çalışma kodum:

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

mükemmel, cazibe ve şablon gibi işler parametre olarak alt sorgu ile tekrar kullanılabilir ..
Zavael

Bu çözüm, temel sorgunuz GROUP BY
Dave R

4

Ayrıca kullanabilirsiniz

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

sayaç değişkenini başlatmak için.


3
@curRowbu sorguyu geçerli oturumda en son çalıştırdığınız zamana ait bir değeri hâlâ olabilir.
Bill Karwin

Doğru, ancak yalnızca aynı bağlantı örneğini yeniden sorguluyorsanız. Bağlantı kapatıldığında yerel değişkenler otomatik olarak atılır.
Ocak

Evet, "şu anki seansta" dediğimde kastettiğim buydu.
Bill Karwin

3

MySQL'in desteklediğini varsayarsak, bunu standart bir SQL alt sorgusuyla kolayca yapabilirsiniz:

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;

Çok sayıda görüntülenen sonuç için, bu biraz yavaş olacak ve bunun yerine kendi kendine katılmaya geçmek isteyeceksiniz.


3

Alan puanına göre sırayla belirli bir kullanıcının konumunu bilmek istiyorsanız, alan puanının mevcut kullanıcı puanından daha yüksek olduğu tablonuzdaki tüm satırı seçmeniz yeterlidir. Ve bu mevcut kullanıcının hangi pozisyonunu bilmek için + 1 olarak döndürülen satır numarasını kullanın.

Tablonuzun olduğunu league_girlve birincil alanınızın olduğunu varsayarsak id, şunu kullanabilirsiniz:

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

0

Orijinal cevabı inanılmaz derecede yararlı buldum ama aynı zamanda eklediğim satır numaralarına göre belirli bir satır kümesini de almak istedim. Bu nedenle, eklediğim satır numarasına başvurabilmek için orijinal cevabın tamamını bir alt sorguya sardım.

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;

Bir alt sorguda bir alt sorguya sahip olmak çok verimli değildir, bu nedenle SQL sunucunuzun bu sorguyu işlemesini veya tüm tabloyu getirip uygulamanın / web sunucusunun satırları işlemden geçirmesini sağlayarak daha iyi bir sonuç alıp almadığınızı test etmeye değer. .

Şahsen benim SQL sunucum fazla meşgul değil, bu yüzden iç içe geçmiş alt sorguları işlemesi tercih edildi.


0

OP'nin bir mysqlcevap istediğini biliyorum ama diğer cevapların benim için işe yaramadığını bulduğum için,

  • Çoğu başarısız oluyor order by
  • Veya çok verimsizdirler ve sorgunuzu şişman bir tablo için çok yavaşlatırlar

Yani benim gibi başkalarına zaman kazandırmak için , veritabanından aldıktan sonra satırı dizine eklemeniz yeterli

PHP'deki örnek:

$users = UserRepository::loadAllUsersAndSortByScore();

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

PHP'de sayfalama için offset ve limit kullanan örnek:

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

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1+($limit*($offset-1));
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.