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?

È stato utile?

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 .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top