Una opción es usar una variable de clasificación, como la siguiente:
SELECT first_name,
age,
gender,
@curRank := @curRank + 1 AS rank
FROM person p, (SELECT @curRank := 0) r
ORDER BY age;
La (SELECT @curRank := 0)
parte permite la inicialización de la variable sin requerir un SET
comando separado .
Caso de prueba:
CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1));
INSERT INTO person VALUES (1, 'Bob', 25, 'M');
INSERT INTO person VALUES (2, 'Jane', 20, 'F');
INSERT INTO person VALUES (3, 'Jack', 30, 'M');
INSERT INTO person VALUES (4, 'Bill', 32, 'M');
INSERT INTO person VALUES (5, 'Nick', 22, 'M');
INSERT INTO person VALUES (6, 'Kathy', 18, 'F');
INSERT INTO person VALUES (7, 'Steve', 36, 'M');
INSERT INTO person VALUES (8, 'Anne', 25, 'F');
Resultado:
+------------+------+--------+------+
| first_name | age | gender | rank |
+------------+------+--------+------+
| Kathy | 18 | F | 1 |
| Jane | 20 | F | 2 |
| Nick | 22 | M | 3 |
| Bob | 25 | M | 4 |
| Anne | 25 | F | 5 |
| Jack | 30 | M | 6 |
| Bill | 32 | M | 7 |
| Steve | 36 | M | 8 |
+------------+------+--------+------+
8 rows in set (0.02 sec)
partition by gender
parte de la función analítica (que "numera" el valor de rango por género no para el resultado general)Aquí hay una solución genérica que asigna un rango denso sobre la partición a las filas. Utiliza variables de usuario:
Observe que las asignaciones de variables se colocan dentro de la
CASE
expresión. Esto (en teoría) se ocupa del orden de la cuestión de la evaluación. SeIS NOT NULL
agrega para manejar la conversión de tipo de datos y los problemas de cortocircuito.PD: Se puede convertir fácilmente al número de fila sobre la partición eliminando todas las condiciones que verifican el empate.
Demostración en db <> fiddle
fuente
ELSE @rank_count := @rank_count + 1
ORDER BY gender, age DESC
?Si bien la respuesta más votada se clasifica, no se divide, puedes hacer una auto-unión para que todo se particione también:
Caso de uso
Respuesta :
fuente
Un ajuste de la versión de Daniel para calcular el percentil junto con el rango. También dos personas con las mismas marcas obtendrán el mismo rango.
Resultados de la consulta para una muestra de datos -
fuente
Combinación de la respuesta de Daniel y Salman. Sin embargo, el rango no cederá a medida que continúe la secuencia con los lazos. En cambio, salta el rango al siguiente. Por lo tanto, el máximo siempre alcanza el recuento de filas.
Esquema y caso de prueba:
Salida:
fuente
Comenzando con MySQL 8, finalmente puede usar funciones de ventana también en MySQL: https://dev.mysql.com/doc/refman/8.0/en/window-functions.html
Su consulta se puede escribir exactamente de la misma manera:
fuente
@Sam, su punto es excelente en concepto, pero creo que entendió mal lo que dicen los documentos de MySQL en la página de referencia, o no entiendo :-), y solo quería agregar esto para que si alguien se siente incómodo con el @ La respuesta de Daniel será más tranquilizador o al menos profundizará un poco más.
Verá que el
"@curRank := @curRank + 1 AS rank"
interiorSELECT
no es "una declaración", es una parte "atómica" de la declaración, por lo que debe ser segura.El documento al que hace referencia continúa para mostrar ejemplos en los que la misma variable definida por el usuario en 2 partes (atómicas) de la declaración, por ejemplo
"SELECT @curRank, @curRank := @curRank + 1 AS rank"
,.Se podría argumentar que
@curRank
se usa dos veces en la respuesta de @ Daniel: (1) el"@curRank := @curRank + 1 AS rank"
y (2) el"(SELECT @curRank := 0) r"
pero ya que el segundo uso es parte delFROM
cláusula, estoy bastante seguro de que se garantiza que se evaluará primero; esencialmente haciéndolo una segunda declaración anterior.De hecho, en la misma página de documentos de MySQL a la que hizo referencia, verá la misma solución en los comentarios: podría ser de donde lo obtuvo @Daniel; Sí, sé que son los comentarios, pero son comentarios en la página de documentos oficiales y eso tiene algo de peso.
fuente
La solución más directa para determinar el rango de un valor dado es contar la cantidad de valores que tiene delante . Supongamos que tenemos los siguientes valores:
30
valores se consideran 3er.40
valores se consideran 6to (rango) o 4to (rango denso)Ahora volvamos a la pregunta original. Aquí hay algunos datos de muestra que se ordenan como se describe en OP (los rangos esperados se agregan a la derecha):
Calcular
RANK() OVER (PARTITION BY Gender ORDER BY Age)
para Sarah , puede usar esta consulta:Calcular
RANK() OVER (PARTITION BY Gender ORDER BY Age)
de todas las filas se puede utilizar esta consulta:Y aquí está el resultado (los valores unidos se agregan a la derecha):
fuente
Si desea clasificar a una sola persona, puede hacer lo siguiente:
Esta clasificación corresponde a la función RANGO de oráculo (donde si tiene personas con la misma edad obtienen la misma clasificación, y la clasificación posterior no es consecutiva).
Es un poco más rápido que usar una de las soluciones anteriores en una subconsulta y seleccionarla para obtener la clasificación de una persona.
Esto se puede usar para clasificar a todos, pero es más lento que las soluciones anteriores.
fuente
Person
aumenta el número de filas en la tabla. Es O (n ^ 2) vs O (n) más lento.Para evitar el " sin embargo " en la respuesta de Erandac en combinación con las respuestas de Daniel y Salman, uno puede usar una de las siguientes "soluciones alternativas de partición"
La clasificación de la partición en la tercera variante en este fragmento de código devolverá números de clasificación continua. Esto conducirá a una estructura de datos similar al
rank() over partition by
resultado. Como ejemplo, ver abajo. En particular, la secuencia de partición siempre comenzará con 1 para cada nueva partición de banco , utilizando este método:fuente
fuente