MySQL ORDER BY'da satır konumunu alır


88

Aşağıdaki MySQL tablosu ile:

+-----------------------------+
+ id INT UNSIGNED             +
+ name VARCHAR(100)           +
+-----------------------------+

Sıralandığında tek bir satırı VE tablodaki diğer satırlar arasındaki konumunu nasıl seçebilirim name ASC? Dolayısıyla, tablo verileri ada göre sıralandığında şöyle görünüyorsa:

+-----------------------------+
+ id | name                   +
+-----------------------------+
+  5 | Alpha                  +
+  7 | Beta                   +
+  3 | Delta                  +
+ .....                       +
+  1 | Zed                    +
+-----------------------------+

BetaO satırın mevcut konumunu alan satırı nasıl seçebilirim ? Aradığım sonuç kümesi şöyle bir şey olurdu:

+-----------------------------+
+ id | position | name        +
+-----------------------------+
+  7 |        2 | Beta        +
+-----------------------------+

Basit ve SELECT * FROM tbl ORDER BY name ASCsonra PHP'deki satırları numaralandırabilirim, ancak yalnızca tek bir satır için potansiyel olarak büyük bir sonuç kümesini yüklemek boşa gider.



Olası MySQL
jberryman

Yanıtlar:


122

Bunu kullan:

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'

... benzersiz bir konum değeri elde etmek için. Bu:

SELECT t.id,
       (SELECT COUNT(*)
          FROM TABLE x
         WHERE x.name <= t.name) AS position,
       t.name    
  FROM TABLE t      
 WHERE t.name = 'Beta'

... bağlara aynı değeri verecektir. IE: İkinci sırada iki değer varsa, ilk sorgu bunlardan birine 2 ve diğerine 3 konum verdiğinde her ikisinin de konumu 2 olacaktır ...


@gerçek: Söylenecek bir şey yok - analitik işlevleri destekleyen bir rakibe geçmekten başka alternatif yok (PostgreSQL, Oracle, SQL Server, DB2 ...)
OMG Ponies

2
@OMGPonies Sonrasında virgül bırak position, ama bu mükemmel.
pierallard

Oldukça eski bir gönderi olduğunu biliyorum, ancak benzer bir çözüme ihtiyacım var. Bununla birlikte, iç birleşimler, gruplama ölçütü ve sıralama kullanılırken, "konum" alanı bunları yok sayar ve değerin tümü karıştırılır. Herhangi bir çözüm var mı?
Daniel

@Daniel yeni bir soru sormalı ve belki de buna başvurmalısınız.
PeerBr

@gerçek, bu tek bir satır için bir sorgu olduğundan, burada önemli bir performans endişesi olmamalıdır. Tam bir listenin sıralarını almaya çalışıyorsanız bu farklıdır, ancak sadece "hile yapabilir" ve puana göre sıralayarak örtük bir sıralama kullanabilirsiniz.
AgmLauncher

20

Aklıma gelen tek yol bu:

SELECT `id`,
       (SELECT COUNT(*) FROM `table` WHERE `name` <= 'Beta') AS `position`,
       `name`
FROM `table`
WHERE `name` = 'Beta'

2
1 İyi numara ... Ancak muhtemelen kullanmak isterdim name <= 'Beta'yerine
Daniel Vassallo

Bu yaklaşım, positionbağlar için aynı değerleri verecektir .
OMG Ponies

(Önceki yorumumu sildim - yanılmışım) ... Ya LIMIT 1oraya bir eklerseniz ? Beraberlik durumunda, beraberliğin son konumu ile sadece bir sıra alacaksınız.
Daniel Vassallo

OP bu namealanın benzersiz olduğunu garanti edebiliyorsa , sorguyu daha karmaşık hale getirmek için hiçbir neden yoktur. Yapamazsa - o zaman bağlı isimler için sonuç beklentilerini bekleyelim.
zerkms

8

Sorgu basitse ve döndürülen sonuç kümesinin boyutu potansiyel olarak büyükse, onu iki sorguya bölmeyi deneyebilirsiniz.

Yalnızca o satırın verilerini almak için daraltılmış filtreleme ölçütlerine sahip ilk sorgu ve ikinci sorgu konumu hesaplamak için COUNTwith WHEREcümlesini kullanır .

Örneğin senin durumunda

Sorgu 1:

SELECT * FROM tbl WHERE name = 'Beta'

Sorgu 2:

SELECT COUNT(1) FROM tbl WHERE name >= 'Beta'

Bu yaklaşımı 2M kaydı olan bir tabloda kullanıyoruz ve bu OMG Ponies'in yaklaşımından çok daha ölçeklenebilir.


5

Diğer cevaplar benim için çok karmaşık görünüyor.

İşte size kolay bir örnek , diyelim ki sütunlu bir tablonuz var:

userid | points

ve kullanıcı kimliklerini puana göre sıralamak ve satır konumunu (kullanıcının "sıralaması") almak istiyorsanız, sonra şunu kullanırsınız:

SET @row_number = 0;

SELECT 
    (@row_number:=@row_number + 1) AS num, userid, points
FROM
    ourtable
ORDER BY points DESC

num size satır konumunu (sıralama) verir.

MySQL 8.0+ sürümüne sahipseniz, ROW_NUMBER () kullanmak isteyebilirsiniz.


2

Tablodaki bir satırın konumu, kaç satırın hedeflenen satırdan "daha iyi" olduğunu gösterir.

Yani, bu satırları saymalısınız.

<'Beta' tableNEREDEN SAYI (*) + 1 SEÇİNname

Beraberlik durumunda en yüksek pozisyon iade edilir.

Mevcut "Beta" satırından sonra aynı adı "Beta" olan başka bir satır eklerseniz, döndürülen konum yine de 2 olacaktır, çünkü bunlar sınıflandırmada aynı yeri paylaşacaktır.

Umarım bu, soru sahibinin sorununu çözdüğüne inandığım için gelecekte benzer bir şey arayacak kişilere yardımcı olur.


2

Çok benzer bir sorunum var, bu yüzden aynı soruyu sormayacağım, ancak burada ne yaptığımı paylaşacağım, ayrıca bir grup ve AVG tarafından sipariş vermek zorunda kaldım. İmzalı ve socorelu öğrenciler var ve onları sıralamak zorundaydım (başka bir deyişle, önce AVG'yi hesapladım, sonra DESC'de sipariş ettim ve sonunda pozisyonu eklemem gerekiyordu (benim için rütbe). şey çok benzer olarak en iyi yanıt ) sorunuma ayarlamak biraz değişikliklerle burada,:

Sonunda position(benim için sıralama) sütununu harici SEÇİM'e koydum

SET @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 

Bu cevabı anlamak, kabul edilenden daha kolaydı. +1
Eric Seastrand

1

Kabul edilen cevabın üzerinden geçiyordum ve biraz karmaşık görünüyordu, bu yüzden işte basitleştirilmiş versiyonu.

SELECT t,COUNT(*) AS position FROM t      
 WHERE name <= 'search string' ORDER BY name

0

Tablonun sırasını ( Dizini ) istediğimde benzer türde problemlerim var order by votes desc. Aşağıdakiler benim için iyi çalışıyor.

Select *, ROW_NUMBER() OVER(ORDER BY votes DESC) as "rank"
From "category_model"
where ("model_type" = ? and "category_id" = ?)

-9

sözdizimi ekleme ile ihtiyacınız olan şey olabilir

LIMIT

öyleyse kullan

SELECT * FROM tbl ORDER BY name ASC LIMIT 1

sadece bir satıra ihtiyacınız varsa ..


bu cevap buradaki sorunu çözmez.
Silmeyi
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.