Unirse a una sola fila de una tabla en MySQL
-
30-09-2019 - |
Pregunta
Tengo dos tablas players
y scores
.
Quiero generar un informe que es como la siguiente:
player first score points
foo 2010-05-20 19
bar 2010-04-15 29
baz 2010-02-04 13
En este momento, mi consulta es como la siguiente:
select p.name player,
min(s.date) first_score,
s.points points
from players p
join scores s on s.player_id = p.id
group by p.name, s.points
necesito el s.points
que se asocia con la fila que vuelve min(s.date)
. Es que ocurre con esta consulta? Es decir, ¿cómo puedo estar seguro de que estoy recibiendo el valor correcto para el s.points
fila unida?
Nota al margen: Me imagino que esto es de alguna manera relacionada con la falta de clasificación densa de MySQL. Cuál es la mejor solución aquí?
Solución
Este es el problema más grande-n-por-grupo que aparece con frecuencia en desbordamiento de pila.
Aquí está mi respuesta habitual:
select
p.name player,
s.date first_score,
s.points points
from players p
join scores s
on s.player_id = p.id
left outer join scores s2
on s2.player_id = p.id
and s2.date < s.date
where
s2.player_id is null
;
En otras palabras, dada la puntuación s, tratar de encontrar un s2 punto para el mismo jugador, pero con una fecha anterior. Si no se encuentra ninguna puntuación anterior, entonces S es la más antigua.
Re tu comentario sobre lazos: Tienes que tener una política para la que se debe usar en caso de empate. Una posibilidad es si utiliza incremento automático claves primarias, el que tiene el menor valor es el anterior. Ver el término adicional en la combinación externa a continuación:
select
p.name player,
s.date first_score,
s.points points
from players p
join scores s
on s.player_id = p.id
left outer join scores s2
on s2.player_id = p.id
and (s2.date < s.date or s2.date = s.date and s2.id < s.id)
where
s2.player_id is null
;
Básicamente es necesario agregar términos de desempate hasta que llegue a una columna que se garantiza que sea único, al menos para el jugador determinado. La clave principal de la tabla es a menudo la mejor solución, pero he visto casos en los que otra columna era adecuado.
En cuanto a los comentarios que he compartido con @OMG los potros, recuerda que este tipo de prestaciones de consulta enormemente a partir del índice derecho.
Otros consejos
La mayoría RDMBS ni siquiera permitirá incluir columnas no agregadas en su cláusula SELECT cuando se utiliza GROUP BY. En MySQL, que va a terminar con los valores de las filas aleatorias para sus columnas no agregadas. Esto es útil si usted realmente tiene el mismo valor en una columna en particular para todas las filas. Por lo tanto, es bueno que MySQL no restringirnos, aunque es una cosa importante de entender.
Un capítulo entero está dedicado a esto en SQL antipatterns .