Vedo che molte persone usano subquery o funzionalità specifiche del fornitore per farlo, ma spesso faccio questo tipo di query senza subquery nel modo seguente. Utilizza un normale SQL standard, quindi dovrebbe funzionare con 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 t1dove non esiste altra riga con la stessa UserIde una data maggiore.
(Ho messo l'identificatore "Date" nei delimitatori perché è una parola riservata SQL.)
In caso affermativo t1."Date" = t2."Date", appare il raddoppio. Di solito le tabelle hanno una auto_inc(seq)chiave, ad es id. Per evitare il raddoppio può essere usato come 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;
Re commento di @Farhan:
Ecco una spiegazione più dettagliata:
Un join esterno tenta di unirsi t1a t2. Per impostazione predefinita, t1vengono restituiti tutti i risultati di e, se è presente una corrispondenza t2, viene anche restituito. Se non esiste una corrispondenza t2per una determinata riga di t1, la query restituisce comunque la riga di t1e utilizza NULLcome segnaposto per tutte t2le colonne. Ecco come funzionano i join esterni in generale.
Il trucco di questa query è progettare la condizione di corrispondenza del join in modo tale che t2debba corrispondere alla stessa userid e ad una maggiore date . L'idea è se esiste una riga in t2cui ha una maggiore date, allora la riga t1è confrontata non può essere il più grande datedi quella userid. Ma se non vi è alcuna corrispondenza, ovvero se non esiste alcuna riga t2con un valore maggiore datedella riga in t1, sappiamo che la riga in t1era la riga con il massimo dateper il dato userid.
In quei casi (quando non c'è corrispondenza), le colonne di t2saranno NULL- anche le colonne specificate nella condizione di join. Quindi è per questo che usiamo WHERE t2.UserId IS NULL, perché stiamo cercando i casi in cui non è stata trovata alcuna riga con una maggiore dateper il dato userid.