Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Busca a linha que tem o valor Max para uma coluna


Vejo que muitas pessoas usam subconsultas ou funções de janela para fazer isso, mas muitas vezes faço esse tipo de consulta sem subconsultas da seguinte maneira. Ele usa SQL simples e padrão, portanto, deve funcionar em qualquer marca de 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;

Em outras palavras:busque a linha de t1 onde não existe outra linha com o mesmo UserId e uma data maior.

(Coloquei o identificador "Data" nos delimitadores porque é uma palavra reservada do SQL.)

Caso t1."Date" = t2."Date" , a duplicação aparece. Normalmente as tabelas têm auto_inc(seq) chave, por exemplo id .Para evitar a duplicação pode ser usado o seguinte:
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;

Comentário de @Farhan:

Segue uma explicação mais detalhada:

Uma junção externa tenta ingressar em t1 com t2 . Por padrão, todos os resultados de t1 são retornados e se há uma correspondência em t2 , ele também é retornado. Se não houver correspondência em t2 para uma determinada linha de t1 , a consulta ainda retornará a linha de t1 , e usa NULL como um espaço reservado para todos os t2 colunas de. É assim que as junções externas funcionam em geral.

O truque nesta consulta é projetar a condição de correspondência da junção de forma que t2 deve corresponder ao mesmo userid , e um maior date . A ideia é se existe uma linha em t2 que tem uma date maior , então a linha em t1 é comparado com não pode ser a maior date para esse userid . Mas se não houver correspondência -- ou seja, se não existir nenhuma linha em t2 com uma date maior do que a linha em t1 -- sabemos que a linha em t1 foi a linha com a maior date para o userid fornecido .

Nesses casos (quando não há correspondência), as colunas de t2 será NULL -- mesmo as colunas especificadas na condição de junção. É por isso que usamos WHERE t2.UserId IS NULL , porque estamos procurando os casos em que nenhuma linha foi encontrada com uma date maior para o userid fornecido .