Vejo muitas pessoas usarem subconsultas ou outros recursos específicos do fornecedor para fazer isso, mas geralmente 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 a mesma data UserId
e uma data maior.
(Coloquei o identificador "Data" nos delimitadores porque é uma palavra reservada ao SQL.)
Caso isso t1."Date" = t2."Date"
ocorra, a duplicação será exibida. Normalmente, as tabelas têm auto_inc(seq)
chave, por exemplo id
. Para evitar a duplicação pode ser usado a seguir:
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 comentário de @Farhan:
Aqui está uma explicação mais detalhada:
Uma junção externa tentativas para se juntar t1
com t2
. Por padrão, todos os resultados de t1
são retornados e, se houver uma correspondência t2
, ele também será retornado. Se não houver correspondência t2
para uma determinada linha de t1
, a consulta ainda retornará a linha de t1
e será usada NULL
como espaço reservado para todas t2
as 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, que t2
deve corresponder à mesma userid
e maior date
. A ideia é que, se existir uma linha t2
com uma maior date
, então a linha na qual t1
ela é comparada não pode ser a melhor date
para isso userid
. Mas se não houver correspondência - ou seja, se nenhuma linha existir t2
com uma maior date
que a linha exibida t1
-, sabemos que a linha in t1
foi a linha com a maior date
para o dado userid
.
Nesses casos (quando não há correspondência), as colunas t2
serão NULL
- mesmo as colunas especificadas na condição de junção. É por isso que usamos WHERE t2.UserId IS NULL
, porque estamos pesquisando os casos em que nenhuma linha foi encontrada com uma maior date
para o dado userid
.