2010-09-01 109 views
69

Con la siguiente tabla de MySQL:MySQL obtener posición de la fila en orden por

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

¿Cómo puedo seleccionar una sola fila y su posición entre las otras filas de la tabla, cuando ordenado por name ASC. Así que si los datos de tabla se parece a esto, cuando se ordena por nombre:

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

¿Cómo podría seleccionar la fila Beta conseguir la posición actual de esa fila? El conjunto de resultados Busco sería algo como esto:

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

que pueda hacer un simple SELECT * FROM tbl ORDER BY name ASC entonces enumerar las filas en PHP, pero parece un desperdicio para cargar un conjunto de resultados potencialmente grande sólo para una sola fila.

+0

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

+0

Posible duplicado de [MySQL - Obtenga el número de fila en select] (http://stackoverflow.com/questions/2520357/mysql-get-row-row-number-on-select) – jberryman

Respuesta

98

Utilice esta:

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' 

... para obtener un valor de posición única. Esto:

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

... dará lazos al mismo valor. IE: si hay dos valores en el segundo lugar, ambos tendrán una posición de 2 cuando la primera consulta dará una posición de 2 a uno de ellos, y 3 a la otra ...

+3

¿Algún comentario sobre el rendimiento? – actual

+0

@actual: no hay nada que decir, no hay otra alternativa que mudarse a un competidor que admita funciones analíticas (PostgreSQL, Oracle, SQL Server, DB2 ...) –

+2

@OMGPonies Simplemente olvide una coma después de 'position', pero es Perfecto. – pierallard

16

Ésta es la única manera que se me ocurre:

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

+1 Buen truco ... Sin embargo, es probable que desee utilizar 'name <= 'Beta' 'en su lugar –

+0

sí, gracias por la corrección – zerkms

+0

Este enfoque dará los mismos valores de' posición' para los vínculos. –

-7

puede ser lo que necesita es con la sintaxis complemento

LÍMITE

a fin de utilizar

SELECT * FROM tbl ORDER BY name ASC LIMIT 1 

if sólo tiene una fila ..

+0

Leyó mal la publicación. Quiere la posición de las filas en el conjunto – Navarr

+0

, esta respuesta no resuelve el problema aquí. Podría considerar eliminarlo –

6

Si la consulta es simple y el tamaño del conjunto de resultados devuelto es potencialmente grande, entonces puede intentar dividirlo en dos consultas.

La primera consulta con un criterio de filtrado estrecho para solo recuperar datos de esa fila, y la segunda consulta usa COUNT con la cláusula WHERE para calcular la posición.

Por ejemplo, en su caso

Consulta 1:

SELECT * FROM tbl WHERE name = 'Beta'

Consulta 2:

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

Utilizamos este enfoque en una mesa con el expediente 2M y esto es mucho más escalable que el enfoque de OMG Ponies.

0

La posición de una fila en la tabla representa cuántas filas son "mejores" que la fila seleccionada.

Por lo tanto, debe contar esas filas.

SELECT COUNT (*) + 1 DE DONDE table, se devuelve la posición más alta name < 'Beta'

En caso de empate.

Si agrega otra fila con el mismo nombre de "Beta" después de la fila "Beta" existente, la posición devuelta sería todavía 2, ya que compartirían el mismo lugar en la clasificación.

Espero que esto ayude a las personas que buscarán algo similar en el futuro, ya que creo que el dueño de la pregunta ya resolvió su problema.

1

Tengo un problema muy similar, es por eso que no haré la misma pregunta, pero compartiré aquí lo que hice, tuve que usar también un grupo y ordené por AVG. Hay estudiantes, con firmas y calificaciones, y tuve que clasificarlos (en otras palabras, calculo primero la AVG, luego los pedí en DESC, y finalmente, tuve que agregar la posición (rango para mí), entonces hizo algo Muy similar como el mejor respuesta aquí, con unos pequeños cambios que se ajustan a mi problema):

que finalmente poner el position (rango para mí) la columna en el exterior SELECCIONAR

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

Esta respuesta fue más fácil de entender que la aceptada. +1 – Eric

Cuestiones relacionadas