Eu tenho uma tabela ("lms_attendance") dos horários de check-in e check-out dos usuários que se parece com isso:
id user time io (enum)
1 9 1370931202 out
2 9 1370931664 out
3 6 1370932128 out
4 12 1370932128 out
5 12 1370933037 in
Estou tentando criar uma exibição dessa tabela que produziria apenas o registro mais recente por ID de usuário, enquanto me fornecia o valor "in" ou "out", algo como:
id user time io
2 9 1370931664 out
3 6 1370932128 out
5 12 1370933037 in
Estou bem perto até agora, mas percebi que as visualizações não aceitam subconsultas, o que está tornando muito mais difícil. A consulta mais próxima que recebi foi:
select
`lms_attendance`.`id` AS `id`,
`lms_attendance`.`user` AS `user`,
max(`lms_attendance`.`time`) AS `time`,
`lms_attendance`.`io` AS `io`
from `lms_attendance`
group by
`lms_attendance`.`user`,
`lms_attendance`.`io`
Mas o que eu recebo é:
id user time io
3 6 1370932128 out
1 9 1370931664 out
5 12 1370933037 in
4 12 1370932128 out
O que é próximo, mas não perfeito. Eu sei que o último grupo de não deveria estar lá, mas sem ele, ele retorna o tempo mais recente, mas não com seu valor relativo de IO.
Alguma ideia? Obrigado!
mysql
sql
greatest-n-per-group
Keith
fonte
fonte
Respostas:
Inquerir:
SQLFIDDLEExample
Resultado:
Solução que funciona sempre:
SQLFIDDLEExample
fonte
Não é necessário tentar reinventar a roda, pois esse é o maior problema comum por grupo . Solução muito boa é apresentada .
Prefiro a solução mais simplista ( consulte SQLFiddle, atualizado de Justin ) sem subconsultas (portanto, fácil de usar nas visualizações):
Isso também funciona em um caso em que existem dois registros diferentes com o mesmo maior valor dentro do mesmo grupo - graças ao truque com
(t1.time = t2.time AND t1.Id < t2.Id)
. Tudo o que estou fazendo aqui é garantir que, quando dois registros do mesmo usuário tiverem o mesmo horário, apenas um seja escolhido. Na verdade, não importa se o critério éId
ou algo mais - basicamente qualquer critério que seja garantido como único faria o trabalho aqui.fonte
t1.time < t2.time
e o min seriat1.time > t2.time
o oposto da minha intuição inicial.t1.time < t2.time
condição se aplica :-)WHERE t2.user IS NULL
é um pouco estranho. Que papel essa linha desempenha?OR (t1.time = t2.time AND t1.Id < t2.Id))
seção?Baseado na resposta do @TMS, gosto porque não há necessidade de subconsultas, mas acho que omitir a
'OR'
peça será suficiente e muito mais simples de entender e ler.se você não estiver interessado em linhas com tempos nulos, poderá filtrá-las na
WHERE
cláusula:fonte
OR
peça é uma péssima idéia se dois registros puderem ter o mesmotime
.Já resolvido, mas apenas para constar, outra abordagem seria criar duas visualizações ...
Clique aqui para vê-lo em ação no SQL Fiddle
fonte
fonte
join (select * from lms_attendance ) b
=join lms_attendance b
fonte
Se você está no MySQL 8.0 ou superior, pode usar as funções do Windows :
Inquerir:
DBFiddleExample
Resultado:
A vantagem que vejo ao usar a solução proposta por Justin é que ela permite selecionar a linha com os dados mais recentes por usuário (ou por ID ou por qualquer outra coisa), mesmo de subconsultas sem a necessidade de uma exibição ou tabela intermediária.
E, caso você esteja executando um HANA, também é ~ 7 vezes mais rápido: D
fonte
Ok, isso pode ser um hack ou propenso a erros, mas de alguma forma isso está funcionando também -
fonte
Tente esta consulta:
fonte
id
eio
são colunas não agregadas, que não podem ser usadas em agroup by
.Possivelmente você pode agrupar por usuário e depois ordenar por tempo desc. Algo como abaixo
fonte
Isso funcionou para mim:
fonte