Tengo una tabla ("lms_attendance") de los horarios de entrada y salida de los usuarios que se ve así:
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
Estoy tratando de crear una vista de esta tabla que solo muestre el registro más reciente por ID de usuario, al tiempo que me da el valor de "entrada" o "salida", así que algo como:
id user time io
2 9 1370931664 out
3 6 1370932128 out
5 12 1370933037 in
Hasta ahora estoy bastante cerca, pero me di cuenta de que las vistas no aceptarán subconsultas, lo que lo hace mucho más difícil. La consulta más cercana que recibí fue:
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`
Pero lo que obtengo es:
id user time io
3 6 1370932128 out
1 9 1370931664 out
5 12 1370933037 in
4 12 1370932128 out
Lo cual está cerca, pero no es perfecto. Sé que el último grupo no debería estar allí, pero sin él, devuelve la última vez, pero no con su valor relativo de IO.
¿Algunas ideas? ¡Gracias!
mysql
sql
greatest-n-per-group
Keith
fuente
fuente
Respuestas:
Consulta:
SQLFIDDLEExample
Resultado:
Solución que funcionará siempre:
SQLFIDDLEExample
fuente
No es necesario intentar reinventar la rueda, ya que este es el problema más grande de n-por-grupo . Se presenta una muy buena solución .
Prefiero la solución más simplista ( vea SQLFiddle, Justin actualizado ) sin subconsultas (por lo tanto, fácil de usar en las vistas):
Esto también funciona en un caso en el que hay dos registros diferentes con el mismo mayor valor dentro del mismo grupo, gracias al truco con
(t1.time = t2.time AND t1.Id < t2.Id)
. Todo lo que estoy haciendo aquí es asegurar que en caso de que dos registros del mismo usuario tengan el mismo tiempo, solo se elija uno. En realidad, no importa si el criterio esId
u otra cosa, básicamente cualquier criterio que se garantice que sea único haría el trabajo aquí.fuente
t1.time < t2.time
y el mínimo seríant1.time > t2.time
lo opuesto a mi intuición inicial.t1.time < t2.time
aplica la condición :-)WHERE t2.user IS NULL
Es un poco extraño. ¿Qué papel juega esta línea?OR (t1.time = t2.time AND t1.Id < t2.Id))
sección?Basado en la respuesta de @TMS, me gusta porque no hay necesidad de subconsultas, pero creo que omitir la
'OR'
parte será suficiente y mucho más fácil de entender y leer.Si no está interesado en filas con tiempos nulos, puede filtrarlas en la
WHERE
cláusula:fuente
OR
parte es una muy mala idea si dos registros pueden tener lo mismotime
.Ya resuelto, pero solo para el registro, otro enfoque sería crear dos vistas ...
Haga clic aquí para verlo en acción en SQL Fiddle
fuente
fuente
join (select * from lms_attendance ) b
=join lms_attendance b
fuente
Si está en MySQL 8.0 o superior, puede usar las funciones de Windows :
Consulta:
DBFiddleExample
Resultado:
La ventaja que veo sobre el uso de la solución propuesta por Justin es que le permite seleccionar la fila con los datos más recientes por usuario (o por id, o por lo que sea) incluso de subconsultas sin la necesidad de una vista o tabla intermedia.
Y en caso de que ejecute una HANA, también es ~ 7 veces más rápido: D
fuente
Ok, esto podría ser un hack o propenso a errores, pero de alguna manera esto también funciona.
fuente
Prueba esta consulta:
fuente
id
yio
son columnas no agregadas, que no se pueden usar en agroup by
.Posiblemente puede agrupar por usuario y luego ordenar por tiempo desc. Algo así como abajo
fuente
Esto funcionó para mí:
fuente