Ich habe eine Tabelle ("lms_attendance") der Ein- und Auscheckzeiten der Benutzer, die folgendermaßen aussieht:
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
Ich versuche, eine Ansicht dieser Tabelle zu erstellen, die nur den neuesten Datensatz pro Benutzer-ID ausgibt, während ich den Wert "in" oder "out" erhalte.
id user time io
2 9 1370931664 out
3 6 1370932128 out
5 12 1370933037 in
Ich bin bisher ziemlich nah dran, aber mir wurde klar, dass Ansichten keine Unterwahlen akzeptieren, was es sehr viel schwieriger macht. Die nächste Anfrage, die ich bekam, war:
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`
Aber was ich bekomme ist:
id user time io
3 6 1370932128 out
1 9 1370931664 out
5 12 1370933037 in
4 12 1370932128 out
Welches ist nah, aber nicht perfekt. Ich weiß, dass die letzte Gruppe von nicht vorhanden sein sollte, aber ohne sie gibt sie die letzte Zeit zurück, aber nicht mit ihrem relativen E / A-Wert.
Irgendwelche Ideen? Vielen Dank!
mysql
sql
greatest-n-per-group
Keith
quelle
quelle
Antworten:
Abfrage:
SQLFIDDLEExample
Ergebnis:
Lösung, die jedes Mal funktioniert:
SQLFIDDLEExample
quelle
Sie müssen nicht versuchen, das Rad neu zu erfinden, da dies das häufigste Problem für jede Gruppe ist . Sehr schöne Lösung wird vorgestellt .
Ich bevorzuge die einfachste Lösung ( siehe SQLFiddle, aktualisierte Justins ) ohne Unterabfragen (daher in Ansichten einfach zu verwenden):
Dies funktioniert auch in einem Fall, in dem es zwei verschiedene Datensätze mit demselben größten Wert innerhalb derselben Gruppe gibt - dank des Tricks mit
(t1.time = t2.time AND t1.Id < t2.Id)
. Ich möchte hier nur sicherstellen, dass für den Fall, dass zwei Datensätze desselben Benutzers dieselbe Zeit haben, nur einer ausgewählt wird. Es spielt eigentlich keine Rolle, ob die KriterienId
oder etwas anderes sind - im Grunde genommen würden alle Kriterien, die garantiert einzigartig sind, den Job hier machen.quelle
t1.time < t2.time
und die minimale Verwendungt1.time > t2.time
sind das Gegenteil meiner anfänglichen Intuition.t1.time < t2.time
Bedingung gilt :-)WHERE t2.user IS NULL
ist ein bisschen seltsam. Welche Rolle spielt diese Linie?OR (t1.time = t2.time AND t1.Id < t2.Id))
Abschnitt klären ?Basierend auf der @ TMS-Antwort gefällt es mir, weil keine Unterabfragen erforderlich sind, aber ich denke, dass das Auslassen des
'OR'
Teils ausreichend und viel einfacher zu verstehen und zu lesen ist.Wenn Sie nicht an Zeilen mit Nullzeiten interessiert sind, können Sie diese in der folgenden
WHERE
Klausel filtern :quelle
OR
Teils ist eine wirklich schlechte Idee, wenn zwei Datensätze dasselbe haben könnentime
.Bereits gelöst, aber nur für die Aufzeichnung, wäre ein anderer Ansatz, zwei Ansichten zu erstellen ...
Klicken Sie hier, um es bei SQL Fiddle in Aktion zu sehen
quelle
quelle
join (select * from lms_attendance ) b
=join lms_attendance b
quelle
Wenn Sie mit MySQL 8.0 oder höher arbeiten, können Sie folgende Fensterfunktionen verwenden :
Abfrage:
DBFiddleExample
Ergebnis:
Der Vorteil, den ich gegenüber der von Justin vorgeschlagenen Lösung sehe , besteht darin, dass Sie die Zeile mit den neuesten Daten pro Benutzer (oder pro ID oder was auch immer) auch aus Unterabfragen auswählen können, ohne dass eine Zwischenansicht oder Tabelle erforderlich ist.
Und falls Sie eine HANA betreiben, ist diese auch ~ 7-mal schneller: D.
quelle
Ok, das könnte entweder ein Hack oder fehleranfällig sein, aber irgendwie funktioniert das auch.
quelle
Versuchen Sie diese Abfrage:
quelle
id
undio
sind nicht aggregierten Spalten, die nicht in einem verwendet werden könnengroup by
.Möglicherweise können Sie nach Benutzer gruppieren und dann nach Zeit absteigen. So etwas wie unten
quelle
Das hat bei mir funktioniert:
quelle