2016-11-03 3 views
1

Ich habe eine Tabelle mit Benutzerkommentare in einem Gästebuch. Spalten sind: ID, Benutzer-ID, Titel, Kommentar, Zeitstempel.Wählen Sie die letzte Zeile für jede Gruppe aus Oracle

Ich muss für jeden Benutzer die neueste Zeile auswählen. Ich habe versucht, durch diese mit der Gruppe zu tun, aber havent es geschafft, weil ich irgendetwas anderes in der gleichen Abfrage auswählen kann nicht, wo ich Gruppe von user_id:

SELECT user_id, MAX(ts) FROM comments GROUP BY user_id 

zum Beispiel in dieser Abfrage i wählen Sie Spalten-ID auch hinzufügen, kippe , kippen und kommentieren. Wie kann das gemacht werden?

Antwort

2

Sie analytische Funktionen verwenden können

SELECT * 
    FROM (SELECT c.*, 
       rank() over (partition by user_id order by ts desc) rnk 
      FROM comments c) 
WHERE rnk = 1 

Je nachdem, wie Sie wollen, Verbindungen zu handhaben (wenn es zwei Zeilen mit demselben user_id und ts sein kann), wird möglicherweise die row_number oder dense_rank Funktion verwenden möchten eher als rank. rank würde erlauben, dass mehrere Zeilen zuerst sind, wenn es eine Gleichheit gab. row_number würde willkürlich eine Reihe zurückgeben, wenn es eine Gleichheit gab. dense_rank würde sich wie rank für die Zeilen verhalten, die für die erste Zeile gebunden sind, würde aber die nächste Zeile als zweite und nicht als dritte Zeile betrachten, wenn zwei Zeilen als erste berücksichtigt werden.

5

Sie können sich auf Ihre Anfrage bauen mit ein JOIN:

select c.* 
from comments c join 
    (select user_id, max(ts) as maxts 
     from comments c2 
     group by user_id 
    ) cc 
    on c.user_id = cc.user_id and c.ts = cc.maxts; 

Es gibt andere Möglichkeiten. Typische Beratung ist row_number() zu verwenden:

select t.* 
from (select c.*, row_number() over (partition by user_id order by ts desc) as seqnum 
     from comments c 
    ) c 
where seqnum = 1; 

Diese beiden Abfragen sind auf subtile Weise anders. Die erste wird Duplikate zurückgeben, wenn der letzte Kommentar für einen Benutzer genau das gleiche ts hatte. Die zweite gibt eine Zeile pro Benutzer zurück.

1

Diese Art von Problemen hat eine sehr einfache und sehr effiziente Lösung mit der dense rank first/last Funktion:

select id, 
     max(user_id) keep (dense_rank last order by ts) over (partition by id) as user_id, 
     max(title) keep (dense_rank last order by ts) over (partition by id) as title, 
     max(comment) keep (dense_rank last order by ts) over (partition by id) as comment, 
     max(ts)                as ts 
from comments; 
Verwandte Themen