Questo è il più grande problema di n-per-gruppo che si presenta frequentemente in 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, prova a trovare un punteggio s2 per lo stesso giocatore, ma con una data precedente. Se non viene trovato alcun punteggio precedente, s è il primo.
Riguardo al tuo commento sui pareggi:devi avere una polizza da usare in caso di pareggio. Una possibilità è che se si utilizzano chiavi primarie a incremento automatico, quella con il valore minimo è quella precedente. Vedi il termine aggiuntivo nel join esterno 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
;
Fondamentalmente devi aggiungere termini di spareggio fino a quando non arrivi a una colonna che è garantita come unica, almeno per un determinato giocatore. La chiave primaria della tabella è spesso la soluzione migliore, ma ho visto casi in cui un'altra colonna era adatta.
Per quanto riguarda i commenti che ho condiviso con @OMG Ponies, ricorda che questo tipo di query beneficia enormemente dell'indice giusto.