it-swarm.com.de

SQL-Abfrage, um die aktuellste Zeile für jede Instanz eines bestimmten Schlüssels abzurufen

Ich versuche, die IP-Adresse, den Benutzer und den neuesten Zeitstempel aus einer Tabelle abzurufen, die sowohl die aktuelle IP-Adresse eines Benutzers als auch eine oder mehrere frühere IPS enthalten kann. Ich möchte eine Zeile für jeden Benutzer, die die neueste IP-Adresse und den zugehörigen Zeitstempel enthält. Wenn also eine Tabelle so aussieht:

username      |  ip      |  time_stamp  
--------------|----------|--------------  
ted           | 1.2.3.4  | 10  
jerry         | 5.6.6.7  | 12  
ted           | 8.8.8.8  | 30  

Ich würde erwarten, dass die Ausgabe der Abfrage lautet:

jerry    |  5.6.6.7   |  12
ted      |  8.8.8.8   |  30  

Kann ich das in einer einzigen SQL-Abfrage tun? Wenn es darauf ankommt, ist das DBMS Postgresql.

63
alanc10n

Versuche dies:

Select u.[username]
      ,u.[ip]
      ,q.[time_stamp]
From [users] As u
Inner Join (
    Select [username]
          ,max(time_stamp) as [time_stamp]
    From [users]
    Group By [username]) As [q]
On u.username = q.username
And u.time_stamp = q.time_stamp
93
Chris Nielsen

Schöne, elegante Lösung mit ROW_NUMBER-Fensterfunktion (unterstützt von PostgreSQL - siehe SQL Fiddle):

SELECT username, ip, time_stamp FROM (
 SELECT username, ip, time_stamp, 
  ROW_NUMBER() OVER (PARTITION BY username ORDER BY time_stamp DESC) rn
 FROM Users
) tmp WHERE rn = 1;
30
Cristi S.

Etwas wie das:

select * 
from User U1
where time_stamp = (
  select max(time_stamp) 
  from User 
  where username = U1.username)

sollte es tun.

7
Kim Gräsman

Bei beiden Antworten wird davon ausgegangen, dass Sie für jeden Benutzer und für time_stamp nur eine Zeile haben. Abhängig von der Anwendung und der Granularität Ihres time_stamp ist dies möglicherweise keine gültige Annahme. Wenn Sie für einen bestimmten Benutzer mit Gleichheit von time_stamp umgehen müssen, müssen Sie eine der oben genannten Antworten erweitern.

Um dies in eine Abfrage zu schreiben, wäre eine andere verschachtelte Unterabfrage erforderlich - die Dinge werden zunehmend unordentlich und die Leistung kann leiden.

Ich hätte das gerne als Kommentar hinzugefügt, aber ich habe noch keinen guten Ruf, also entschuldigen Sie mich als neue Antwort!

3
user2323503

Kommentare können noch nicht geschrieben werden, aber die Antwort von @Cristi S ist für mich ein Genuss. 

In meinem Szenario musste ich nur die letzten 3 Datensätze in Lowest_Offers für alle product_ids aufbewahren.

Er muss seine SQL zum Löschen überarbeiten - dachte, dies wäre in Ordnung, aber die Syntax ist falsch.

DELETE from (
SELECT product_id, id, date_checked,
  ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY date_checked DESC) rn
FROM lowest_offers
) tmp WHERE > 3;
2
err1

Ich verwende das, weil ich Ergebnisse aus einer anderen Tabelle zurückgebe. Obwohl ich versuche, den verschachtelten Join zu vermeiden, wenn er mit einem Schritt weniger hilft. Naja. Es gibt das gleiche zurück.

select
users.userid
, lastIP.IP
, lastIP.maxdate

from users

inner join (
    select userid, IP, datetime
    from IPAddresses
    inner join (
        select userid, max(datetime) as maxdate
        from IPAddresses
        group by userid
        ) maxIP on IPAddresses.datetime = maxIP.maxdate and IPAddresses.userid = maxIP.userid
    ) as lastIP on users.userid = lastIP.userid
0
jawz101