J'ai un tableau ("lms_attendance") des heures d'arrivée et de départ des utilisateurs qui ressemble à ceci:
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
J'essaie de créer une vue de cette table qui afficherait uniquement l'enregistrement le plus récent par identifiant d'utilisateur, tout en me donnant la valeur «in» ou «out», donc quelque chose comme:
id user time io
2 9 1370931664 out
3 6 1370932128 out
5 12 1370933037 in
Je suis assez proche jusqu'à présent, mais j'ai réalisé que les vues n'accepteraient pas les sous-requêtes, ce qui rend les choses beaucoup plus difficiles. La requête la plus proche que j'ai reçue était:
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`
Mais ce que j'obtiens c'est:
id user time io
3 6 1370932128 out
1 9 1370931664 out
5 12 1370933037 in
4 12 1370932128 out
Ce qui est proche, mais pas parfait. Je sais que le dernier groupe de by ne devrait pas être là, mais sans lui, il renvoie l'heure la plus récente, mais pas avec sa valeur IO relative.
Des idées? Merci!
Réponses:
Requete:
SQLFIDDLEExample
Résultat:
Solution qui fonctionnera à chaque fois:
SQLFIDDLEExample
la source
Inutile d'essayer de réinventer la roue, car il s'agit du problème le plus fréquent par groupe . Une très belle solution est présentée .
Je préfère la solution la plus simpliste ( voir SQLFiddle, mise à jour de Justin ) sans sous-requêtes (donc facile à utiliser dans les vues):
Cela fonctionne également dans le cas où il y a deux enregistrements différents avec la même plus grande valeur dans le même groupe - grâce à l'astuce avec
(t1.time = t2.time AND t1.Id < t2.Id)
. Tout ce que je fais ici est d'assurer que dans le cas où deux enregistrements du même utilisateur ont la même heure, un seul est choisi. Peu importe si le critère estId
ou quelque chose d'autre - fondamentalement, tout critère garanti unique ferait le travail ici.la source
t1.time < t2.time
et le min seraitt1.time > t2.time
qui est le contraire de mon intuition initiale.t1.time < t2.time
condition s'applique :-)WHERE t2.user IS NULL
est un peu étrange. Quel rôle joue cette ligne?OR (t1.time = t2.time AND t1.Id < t2.Id))
section?Basé sur la réponse @TMS, je l'aime bien car il n'y a pas besoin de sous-requêtes mais je pense que l'omission de la
'OR'
partie sera suffisante et beaucoup plus simple à comprendre et à lire.si vous n'êtes pas intéressé par les lignes avec des temps nuls, vous pouvez les filtrer dans la
WHERE
clause:la source
OR
partie est une très mauvaise idée si deux enregistrements peuvent avoir la même chosetime
.Déjà résolu, mais juste pour mémoire, une autre approche serait de créer deux vues ...
Cliquez ici pour le voir en action chez SQL Fiddle
la source
la source
join (select * from lms_attendance ) b
=join lms_attendance b
la source
Si vous êtes sur MySQL 8.0 ou supérieur, vous pouvez utiliser les fonctions Windows :
Requete:
DBFiddleExample
Résultat:
L'avantage que je vois par rapport à l'utilisation de la solution proposée par Justin est qu'elle vous permet de sélectionner la ligne avec les données les plus récentes par utilisateur (ou par identifiant, ou par autre) même à partir de sous-requêtes sans avoir besoin d'une vue ou d'un tableau intermédiaire.
Et si vous exécutez un HANA, il est également ~ 7 fois plus rapide: D
la source
Ok, cela peut être un piratage ou une source d'erreur, mais d'une manière ou d'une autre, cela fonctionne aussi bien-
la source
Essayez cette requête:
la source
id
et ceio
sont des colonnes non agrégées, qui ne peuvent pas être utilisées dans un fichiergroup by
.Vous pouvez éventuellement faire un groupe par utilisateur, puis classer par ordre chronologique. Quelque chose comme ci-dessous
la source
Cela a fonctionné pour moi:
la source