Erstellen Sie eine SQL-Abfrage, um die neuesten Datensätze abzurufen


72

Ich erstelle ein Statusboard-Modul für mein Projektteam. Über die Statusanzeige kann der Benutzer seinen Status als "Ein" oder "Aus" festlegen und eine Notiz bereitstellen. Ich hatte vor, alle Informationen in einer einzigen Tabelle zu speichern ... und ein Beispiel für die Daten folgt:

Date               User         Status    Notes
-------------------------------------------------------
1/8/2009 12:00pm   B.Sisko      In        Out to lunch    
1/8/2009 8:00am    B.Sisko      In  
1/7/2009 5:00pm    B.Sisko      In    
1/7/2009 8:00am    B.Sisko      In    
1/7/2009 8:00am    K.Janeway    In   
1/5/2009 8:00am    K.Janeway    In    
1/1/2009 8:00am    J.Picard     Out       Vacation  

Ich möchte die Daten abfragen und den neuesten Status für jeden Benutzer zurückgeben. In diesem Fall würde meine Abfrage die folgenden Ergebnisse zurückgeben:

Date               User         Status    Notes
-------------------------------------------------------  
1/8/2009 12:00pm   B.Sisko      In        Out to lunch    
1/7/2009 8:00am    K.Janeway    In   
1/1/2009 8:00am    J.Picard     Out       Vacation  

Ich versuche, TRANSACT-SQL herauszufinden, um dies zu ermöglichen. Jede Hilfe wäre dankbar.

Antworten:


83

Aggregieren Sie in einer von Unterabfragen abgeleiteten Tabelle und verbinden Sie sich dann mit dieser.

 Select Date, User, Status, Notes 
    from [SOMETABLE]
    inner join 
    (
        Select max(Date) as LatestDate, [User]
        from [SOMETABLE]
        Group by User
    ) SubMax 
    on [SOMETABLE].Date = SubMax.LatestDate
    and [SOMETABLE].User = SubMax.User 

4
Dies wird als abgeleitete Tabelle bezeichnet.
SurroundedByFish

7
Seien Sie vorsichtig, wenn die abgeleitete Tabelle Duplikate für {LatestDate, User}
alphadogg

2
Verlassen Sie sich niemals auf die Einzigartigkeit, es sei denn, die Datenbank garantiert dies. Ich würde diesen Ansatz niemals der Antwort von SQLMenace empfehlen, da versehentliche Duplikate im Ergebnis zu einem unerwarteten Downstream-Verhalten führen können. (Das beste Beispiel für einen Fehler hier ist ein Skript-Update, das dazu führt, dass einige Statusänderungen gleichzeitig landen.)
Andrew Hill

76

Auf andere Weise wird die Tabelle nur einmal anstatt zweimal gescannt, wenn Sie eine Unterabfrage verwenden

Nur SQL Server 2005 und höher

select Date, User, Status, Notes 
from (
       select m.*, row_number() over (partition by user order by Date desc) as rn
       from [SOMETABLE] m
     ) m2
where m2.rn = 1;

Magic, ich konnte knifflige Abfragen lösen, indem ich 3 Tabellen verband und nur den neuesten Eintrag für jeden Typ basierend auf diesem Code auswählte. Vielen Dank!
Sopuli

1
Dies hat im Ausführungsplan die gleichen Kosten wie die akzeptierte Antwort. Wenn Sie jedoch nach mehreren Spalten gruppieren müssen, z. B. orgID, Monat, Jahr, ist diese Antwort semantisch sauberer.
Gooddadmike

Dadurch wird der Datensatz zufällig aus allen Datensätzen ausgewählt, die je nach Reihenfolge zuerst gleich sind.
Andrew Hill

11

Die abgeleitete Tabelle würde funktionieren, aber wenn dies SQL 2005 ist, könnten ein CTE und ROW_NUMBER sauberer sein:

WITH UserStatus (User, Date, Status, Notes, Ord)
as
(
SELECT Date, User, Status, Notes, 
     ROW_NUMBER() OVER (PARTITION BY User ORDER BY Date DESC)
FROM [SOMETABLE]
)

SELECT User, Date, Status, Notes from UserStatus where Ord = 1

Dies würde auch die Anzeige der neuesten x-Status von jedem Benutzer erleichtern.


6

Ein weiterer einfacher Weg:

SELECT Date, User, Status, Notes  
FROM Test_Most_Recent 
WHERE Date in ( SELECT MAX(Date) from Test_Most_Recent group by User)

3
Wird diese Abfrage nicht schief gehen, wenn zwei Benutzer gleichzeitig ihren Status aktualisieren, aber diese Zeit ist nicht die neueste Aktivität für einen von ihnen?
SooDesuNe

Mahesh, Sie müssen Ihre Antwort unter Berücksichtigung des Kommentars von @ SooDesuNe aktualisieren.
Sunny R Gupta

Verwenden Sie SELECTS nicht in WHERE-Klauseln, wenn Sie helfen können. Es sei denn, es ist eine einmalige Sache, die Sie nachschlagen müssen. Wenn dies in einem gespeicherten Prozess geschieht, verlängert sich die Zeit für die Rückgabe der Ergebnisse erheblich. Besonders auf großen Tischen.
Argyle Ghost

0

Fügen Sie jedem Datensatz einen automatisch inkrementierenden Primärschlüssel hinzu, z. B. UserStatusId.

Dann könnte Ihre Anfrage so aussehen:

select * from UserStatus where UserStatusId in
(
    select max(UserStatusId) from UserStatus group by User
)

Datum Benutzerstatus Hinweise

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.