Vedo che molte persone usano sottoquery o altre funzioni della finestra per farlo, ma spesso eseguo questo tipo di query senza sottoquery nel modo seguente. Utilizza un semplice SQL standard, quindi dovrebbe funzionare in qualsiasi marca di RDBMS.
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON (t1.UserId = t2.UserId AND t1."Date" < t2."Date")
WHERE t2.UserId IS NULL;
In altre parole:recupera la riga da t1
dove non esistono altre righe con lo stesso UserId
e una data maggiore.
(Ho inserito l'identificatore "Date" nei delimitatori perché è una parola riservata SQL.)
Nel caso in cui t1."Date" = t2."Date"
, appare il raddoppio. Di solito le tabelle hanno auto_inc(seq)
chiave, ad es. id
.Per evitare il raddoppio si può utilizzare quanto segue:
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON t1.UserId = t2.UserId AND ((t1."Date" < t2."Date")
OR (t1."Date" = t2."Date" AND t1.id < t2.id))
WHERE t2.UserId IS NULL;
Commento di @Farhan:
Ecco una spiegazione più dettagliata:
Un join esterno tenta di entrare in t1
con t2
. Per impostazione predefinita, tutti i risultati di t1
vengono restituiti e se c'è una corrispondenza in t2
, viene anche restituito. Se non c'è corrispondenza in t2
per una data riga di t1
, la query restituisce comunque la riga di t1
e utilizza NULL
come segnaposto per tutto t2
le colonne di È così che funzionano gli outer join in generale.
Il trucco in questa query è progettare la condizione di corrispondenza del join in modo tale che t2
deve corrispondere a uguale userid
e un maggiore date
. L'idea è se esiste una riga in t2
che ha una date
maggiore , quindi la riga in t1
viene confrontato con impossibile essere la migliore date
per quel userid
. Ma se non c'è corrispondenza, cioè se non esiste una riga in t2
con una date
maggiore rispetto alla riga in t1
-- sappiamo che la riga in t1
era la riga con la date
maggiore per il dato userid
.
In questi casi (quando non c'è corrispondenza), le colonne di t2
sarà NULL
-- anche le colonne specificate nella condizione di unione. Ecco perché utilizziamo WHERE t2.UserId IS NULL
, perché stiamo cercando i casi in cui non è stata trovata alcuna riga con una date
maggiore per il dato userid
.