web-dev-qa-db-ja.com

特定のキーの各インスタンスの最新の行を取得するSQLクエリ

ユーザーの現在のIPと1つ以上の以前のIPの両方を含むテーブルから、IP、ユーザー、および最新のタイムスタンプを取得しようとしています。最新のIPと関連するタイムスタンプを含むユーザーごとに1行が必要です。したがって、テーブルが次のようになっている場合:

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

クエリの出力は次のようになります。

jerry    |  5.6.6.7   |  12
ted      |  8.8.8.8   |  30  

これを単一のSQLクエリで実行できますか?重要な場合、DBMSはPostgresqlです。

64
alanc10n

これを試して:

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

ROW_NUMBERウィンドウ関数を使用したエレガントなソリューション(PostgreSQLでサポート-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;
31
Cristi S.

このようなもの:

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

それを行う必要があります。

8
Kim Gräsman

上記の答えは両方とも、各ユーザーとtime_stampに対して1行しかないことを前提としています。アプリケーションとtime_stampの粒度によっては、これは有効な仮定ではない場合があります。特定のユーザーのtime_stampの関係を処理する必要がある場合は、上記の回答のいずれかを拡張する必要があります。

これを1つのクエリで記述するには、別のネストされたサブクエリが必要になります-物事がさらに面倒になり、パフォーマンスが低下する可能性があります。

これをコメントとして追加したかったのですが、まだ50の評判はありませんので、新しい回答として投稿してすみません!

3
user2323503

まだコメントを投稿することはできませんが、@ Cristi Sの答えは私にとってはうまいことです。

私のシナリオでは、すべてのproduct_idについて、Lowest_Offersの最新の3レコードのみを保持する必要がありました。

SQLを削除して削除する必要があります-これは問題ないと思いますが、構文が間違っています。

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

別のテーブルから結果を返すため、これを使用しています。ネストされた結合を回避しようとしていますが、ステップが1つ減ると役立ちます。しかたがない。同じものを返します。

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