SQL查询以获取给定键的每个实例的最新行

时间:2009-07-16 20:23:16

标签: sql postgresql greatest-n-per-group

我正在尝试从表中获取ip,用户和最新时间​​戳,该表可能包含用户的当前ip和一个或多个先前的ips。我想为每个用户提供一行,其中包含最新的ip和相关的时间戳。因此,如果表格如下所示:

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。

6 个答案:

答案 0 :(得分:93)

试试这个:

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

答案 1 :(得分:31)

使用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;

答案 2 :(得分:8)

这样的事情:

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

应该这样做。

答案 3 :(得分:3)

上述两个答案都假设每个用户和time_stamp只有一行。根据应用程序和time_stamp的粒度,这可能不是一个有效的假设。如果您需要为给定用户处理time_stamp的关系,则需要扩展上面给出的答案之一。

在一个查询中写这个需要另一个嵌套的子查询 - 事情会变得更加混乱,性能可能会受到影响。

我本来希望将此添加为评论,但我还没有50个声誉,所以很抱歉发布新答案!

答案 4 :(得分:2)

还不能发表评论,但@Cristi S的答案对我有用。

在我的场景中,我需要在Lowest_Offers中仅保留所有product_ids中最近的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;

答案 5 :(得分:0)

我一直在使用它,因为我正在从另一个表返回结果。虽然我试图避免嵌套连接,如果它有助于减少一步。那好吧。它返回相同的东西。

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