Como faço para lidar com os laços quando a classificação resulta em MySQL?
-
21-09-2019 - |
Pergunta
Como lida com os laços quando a classificação resulta em uma consulta MySQL? Simplifiquei os nomes e colunas da tabela neste exemplo, mas deve ilustrar meu problema:
SET @rank=0;
SELECT student_names.students,
@rank := @rank +1 AS rank,
scores.grades
FROM student_names
LEFT JOIN scores ON student_names.students = scores.students
ORDER BY scores.grades DESC
Imagine que a consulta acima produz:
Students Rank Grades
=======================
Al 1 90
Amy 2 90
George 3 78
Bob 4 73
Mary 5 NULL
William 6 NULL
Embora Al e Amy tenham a mesma nota, um é classificado mais alto que o outro. Amy foi arrancada. Como posso fazer isso para que Amy e Al tenham o mesmo ranking, para que ambos tenham uma classificação de 1. Além disso, William e Mary não fizeram o teste. Eles ensacaram aula e estavam fumando no quarto do garoto. Eles devem estar amarrados para o último lugar.
A classificação correta deve ser:
Students Rank Grades
========================
Al 1 90
Amy 1 90
George 2 78
Bob 3 73
Mary 4 NULL
William 4 NULL
Se alguém tiver algum conselho, por favor me avise.
Solução
EDITAR: Este é o MySQL 4.1+ suportado
Usar:
SELECT st.name,
sc.grades,
CASE
WHEN @grade = COALESCE(sc.grades, 0) THEN @rownum
ELSE @rownum := @rownum + 1
END AS rank,
@grade := COALESCE(sc.grades, 0)
FROM STUDENTS st
LEFT JOIN SCORES sc ON sc.student_id = st.id
JOIN (SELECT @rownum := 0, @grade := NULL) r
ORDER BY sc.grades DESC
Você pode usar uma junção cruzada (no MySQL, uma junção interna sem nenhum critério) para declarar e usar uma variável sem usar um separado SET
declaração.
Você precisa da Coalesce para lidar adequadamente com os nulos.
Outras dicas
Parece uma regra de middleware que seria melhor expressa no código que ficava entre o banco de dados e o cliente.
Se isso não for possível, eu recomendaria um procedimento armazenado no MySQL para executar a consulta ao escrever e modificar os resultados usando um cursor e uma matriz.