2010-09-01 9 views
69

Mit der folgenden MySQL-Tabelle erhalten:MySQL Zeilenposition in ORDER BY

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

Wie kann ich eine einzelne Reihe und seine Position unter den anderen Zeilen in der Tabelle auswählen, wenn sie von name ASC sortiere. Wenn also die Tabellendaten wie folgt aussehen, wenn nach Namen sortiert:

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

Wie kann ich die Beta Reihe wähle die aktuelle Position dieser Reihe zu bekommen? Die Ergebnismenge Ich suche würde wie folgt sein:

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

Ich kann eine einfache SELECT * FROM tbl ORDER BY name ASC tun dann die Zeilen in PHP aufzuzählen, aber es scheint verschwenderisch eine potentiell große resultset nur für eine einzelne Zeile zu laden.

+0

http://stackoverflow.com/questions/2520357/mysql-get-row-number-on-select –

+0

Mögliche Duplikat von [MySQL - Get Zeile Nummer auf Wählen Sie] (http://Stackoverflow.com/questions/2520357/mysql-get-row-number-on-select) – jberryman

Antwort

98

Verwendung:

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' 

... einen eindeutigen Positionswert zu erhalten. Dies ist:

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

... wird den gleichen Wert geben. IE: Wenn es zwei Werte an zweiter Stelle gibt, haben sie beide eine Position von 2, wenn die erste Abfrage eine Position von 2 zu einer von ihnen gibt, und 3 zu der anderen ...

+3

Kommentare zur Leistung? – actual

+0

@actual: Es gibt nichts zu sagen - es gibt keine Alternative, außer zu einem Wettbewerber, der analytische Funktionen (PostgreSQL, Oracle, SQL Server, DB2 ...) unterstützt –

+2

@OMGPonies Vergessen Sie einfach ein Komma nach 'Position', aber es ist perfekt. – pierallard

16

Dies ist der einzige Weg, die ich mir vorstellen kann:

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

+1 Nizza Trick ... Allerdings würden Sie wahrscheinlich 'name <= 'Beta' verwenden möchten 'stattdessen –

+0

yep, danke für die Korrektur – zerkms

+0

Dieser Ansatz wird die gleichen' Position'-Werte für Bindungen geben. –

-7

kann sein, was Sie

LIMIT

so

SELECT * FROM tbl ORDER BY name ASC LIMIT 1 
brauchen, ist mit Add-Syntax

wenn Diese brauchen Sie nur eine Zeile ..

+0

Sie haben den Beitrag falsch gelesen. Er will die Zeilenposition im Set – Navarr

+0

Diese Antwort löst das Problem hier nicht. Sie könnten darüber nachdenken, es zu löschen –

6

Wenn die Abfrage ist einfach und die Größe der zurückgegebenen Ergebnismenge ist möglicherweise groß, dann können Sie versuchen, sie in zwei Abfragen aufzuteilen.

Die erste Abfrage mit einem Einschränkungsfilterungskriterium, um nur Daten dieser Zeile abzurufen, und die zweite Abfrage COUNT mit WHERE-Klausel, um die Position zu berechnen.

Zum Beispiel in Ihrem Fall

Abfrage 1:

SELECT * FROM tbl WHERE name = 'Beta'

Abfrage 2:

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

Wir verwenden diesen Ansatz in einer Tabelle mit 2M Aufzeichnung und das ist viel besser skalierbar als der Ansatz von OMG Ponies.

0

Die Position einer Zeile in der Tabelle gibt an, wie viele Zeilen "besser" sind als die Zielzeile.

Sie müssen also diese Zeilen zählen.

SELECT COUNT (*) FROM table + 1 WHERE name < 'beta'

Im Falle eines Gleichstands, die höchste Position zurückgeführt wird.

Wenn Sie nach der vorhandenen "Beta" -Zeile eine weitere Zeile mit dem gleichen Namen "Beta" hinzufügen, wäre die zurückgegebene Position immer noch 2, da sie denselben Platz in der Klassifizierung haben.

Hoffe das hilft Menschen, die in Zukunft etwas ähnliches suchen werden, da ich glaube, dass der Fragesteller sein Problem bereits gelöst hat.

1

Ich habe ein sehr sehr ähnliches Problem, deshalb werde ich nicht die gleiche Frage stellen, aber ich werde hier teilen, was ich getan habe, musste ich auch eine Gruppe verwenden, und durch AVG bestellen. Es gibt Studenten, mit Unterschriften und Socore, und ich musste sie ordnen (mit anderen Worten, ich zuerst die AVG berechnen, dann in DESC bestellen, und dann musste ich schließlich die Position (Rang für mich) hinzufügen, also ich tat etwas Sehr ähnlich als beste Antwort hier, mit einer wenig Veränderungen, die zu meinem Problem anpassen):

ich habe endlich den position (Rang für mich) Spalte in den SELECT externen

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 
+0

Diese Antwort war leichter zu verstehen als die akzeptierte. +1 – Eric