2016-11-03 2 views
1

У меня есть таблица с комментариями пользователей в гостевой книге. Столбцы: id, user_id, заголовок, комментарий, отметка времени.Выберите последнюю строку для каждой группы из oracle

Мне нужно выбрать последнюю строку для каждого пользователя. Я пытался сделать это с группой по но нету удалось это потому, что я не могу выбрать что-нибудь еще в том же запросе, в котором я группа по user_id:

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

, например, в этом запросе я могу добавить также выбрать столбцы идентификатор , tilte и комментарий. Как это может быть сделано?

ответ

2

Вы можете использовать аналитические функции

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

В зависимости от того, как вы хотите обрабатывать связи (если может быть две строки с одинаковыми user_id и ts), вы можете использовать функцию row_number или dense_rank скорее чем rank. rank разрешил бы несколько строк быть первым, если бы была связь. row_number произвольно возвратил бы одну строку, если бы была связь. dense_rank будет вести себя как rank для строк, привязанных для первого, но рассмотрит следующую строку как вторую, а не третью, предполагая, что две строки привяжутся для первого.

5

Вы можете строить свой запрос с помощью 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; 

Есть и другие способы. Типичный совет использовать row_number():

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; 

Эти два запроса несколько отличаются. Первый будет возвращать дубликаты, если последний комментарий для пользователя был точно таким же ts. Второй возвращает одну строку для каждого пользователя.

1

Этот тип задач имеет очень простое и очень эффективное решение с dense rank first/last функции:

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; 
Смежные вопросы