Oracle
 sql >> Database >  >> RDS >> Oracle

Recupera la riga che ha il valore massimo per una colonna

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 .