PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Trova la serie più lunga di punteggi perfetti per giocatore

A problema davvero.

Supponendo:

  • Le "serie" non vengono interrotte dalle righe di altri giocatori.
  • Tutte le colonne sono definite NOT NULL . (Altrimenti devi fare di più.)

Questo dovrebbe essere il più semplice e veloce in quanto richiede solo due veloci row_number() funzioni della finestra :

SELECT DISTINCT ON (player_id)
       player_id, count(*) AS seq_len, min(ts) AS time_began
FROM  (
   SELECT player_id, points, ts
        , row_number() OVER (PARTITION BY player_id ORDER BY ts) 
        - row_number() OVER (PARTITION BY player_id, points ORDER BY ts) AS grp
   FROM   tbl
   ) sub
WHERE  points = 100
GROUP  BY player_id, grp  -- omit "points" after WHERE points = 100
ORDER  BY player_id, seq_len DESC, time_began DESC;

db<>violino qui

Usando il nome della colonna ts invece di time , che è una parola riservata nell'SQL standard. È consentito in Postgres, ma con limitazioni ed è comunque una cattiva idea usarlo come identificatore.

Il "trucco" consiste nel sottrarre i numeri di riga in modo che le righe consecutive rientrino nello stesso gruppo (grp ) per (player_id, points) . Allora filtra quelli con 100 punti, aggregati per gruppo e restituisci solo il risultato più lungo e più recente per giocatore.
Spiegazione di base per la tecnica:

Possiamo usare GROUP BY e DISTINCT ON nello stesso SELECT , GROUP BY viene applicato prima DISTINCT ON . Considera la sequenza di eventi in un SELECT domanda:

Informazioni su DISTINCT ON :