ゲストブックにユーザーのコメントが記載されたテーブルがあります。列は、id、user_id、title、comment、timestampです。
ユーザーごとに最新の行を選択する必要があります。私はこれをgroup byで実行しようとしましたが、同じクエリでuser_idでグループ化する他のものを選択できないため、管理していません。
SELECT user_id, MAX(ts) FROM comments GROUP BY user_id
たとえば、このクエリでは、列id、tilte、およびコメントを選択することもできません。これはどのように行うことができますか?
分析関数を使用できます
SELECT *
FROM (SELECT c.*,
rank() over (partition by user_id order by ts desc) rnk
FROM comments c)
WHERE rnk = 1
タイの処理方法に応じて(同じuser_id
とts
の2つの行が存在する場合)、row_number
またはdense_rank
関数を使用できます。 rank
ではなく。 rank
を使用すると、同数の場合に複数の行を最初にできます。 row_number
は、同数の場合、任意に1行を返します。 dense_rank
は、最初に関連付けられた行に対してはrank
のように動作しますが、2つの行が最初に関連付けられていると仮定して、次の行を3番目ではなく2番目と見なします。
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;
_
これら2つのクエリは微妙に異なります。最初のコメントは、ユーザーの最新のコメントがまったく同じts
の場合に重複を返します。 2番目は、ユーザーごとに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;