Unirsi singola riga da una tabella in MySQL
-
30-09-2019 - |
Domanda
Ho due tabelle players
e scores
.
voglio generare un rapporto che sembra qualcosa di simile:
player first score points
foo 2010-05-20 19
bar 2010-04-15 29
baz 2010-02-04 13
In questo momento, la mia domanda simile a questa:
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
ho bisogno del s.points
che è associato con la riga che restituisce min(s.date)
. È che accadendo con questa ricerca? Cioè, come posso essere certo che sto ottenendo il valore s.points
corretto per la riga unito?
Nota a margine: Immagino che questo sia in qualche modo legato alla mancanza di classifica denso di MySQL. Qual è la soluzione migliore qui?
Soluzione
Questo è il problema più grande-n-per-gruppo che si presenta di frequente su Stack Overflow.
Ecco la mia solita risposta:
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
;
In altre parole, dato il punteggio s, cercare di trovare un s2 punteggio per lo stesso giocatore, ma con una data precedente. Se non viene trovato alcun punteggio in precedenza, allora S è il più antico uno.
Re i suoi commenti su legami: Bisogna avere una politica per la quale usare in caso di parità. Una possibilità è che se si utilizza incremento automatico chiavi primarie, quello con il valore minimo è il meno un. Vedere il termine supplementare nel outer join di seguito:
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
;
In sostanza è necessario aggiungere termini tie-break fino ad arrivare fino a una colonna che è garantito per essere unico, almeno per il giocatore dato. La chiave primaria della tabella è spesso la soluzione migliore, ma ho visto casi in cui un'altra colonna era adatto.
Per quanto riguarda i commenti che ho condiviso con @OMG pony, ricordate che questo tipo di prestazioni di query enormemente dall'indice di destra.
Altri suggerimenti
La maggior parte RDMBS sarà nemmeno permetterà di includere le colonne non di aggregazione nella vostra clausola SELECT quando si utilizza GROUP BY. In MySQL, vi ritroverete con i valori da filari casuali per le colonne non di aggregazione. Questo è utile se in realtà hanno lo stesso valore in una particolare colonna per tutte le righe. Pertanto, è bello che MySQL non limita noi, anche se è una cosa importante da capire.
Un intero capitolo è dedicato a questo in SQL antipattern .