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 t1
dove non esiste altra riga con la stessa UserId
e 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 t1
a t2
. Per impostazione predefinita, t1
vengono restituiti tutti i risultati di e, se è presente una corrispondenza t2
, viene anche restituito. Se non esiste una corrispondenza t2
per una determinata riga di t1
, la query restituisce comunque la riga di t1
e utilizza NULL
come segnaposto per tutte t2
le 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 t2
debba corrispondere alla stessa userid
e ad una maggiore date
. L'idea è se esiste una riga in t2
cui ha una maggiore date
, allora la riga t1
è confrontata non può essere il più grande date
di quella userid
. Ma se non vi è alcuna corrispondenza, ovvero se non esiste alcuna riga t2
con un valore maggiore date
della riga in t1
, sappiamo che la riga in t1
era la riga con il massimo date
per il dato userid
.
In quei casi (quando non c'è corrispondenza), le colonne di t2
saranno 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 date
per il dato userid
.