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

时间:2021-03-12 12:27:05

I'm trying to get the ip, user, and most recent timestamp from a table which may contain both the current ip for a user and one or more prior ips. I'd like one row for each user containing the most recent ip and the associated timestamp. So if a table looks like this:

我正在尝试从一个表中获取ip、用户和最近的时间戳,这个表可能包含一个用户的当前ip和一个或多个以前的ip。我希望每个用户有一行包含最新的ip和相关的时间戳。如果一个表格是这样的

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

I'd expect the output of the query to be:

我希望查询的输出是:

jerry    |  5.6.6.7   |  12
ted      |  8.8.8.8   |  30  

Can I do this in a single sql query? In case it matters, the DBMS is Postgresql.

我可以在一个sql查询中实现这一点吗?如果重要的话,DBMS是Postgresql。

6 个解决方案

#1


90  

Try this:

试试这个:

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

#2


29  

Nice elegant solution with ROW_NUMBER window function (supported by PostgreSQL - see in SQL Fiddle):

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

#3


7  

Something like this:

是这样的:

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

should do it.

应该这样做。

#4


3  

Both of the above answers assume that you only have one row for each user and time_stamp. Depending on the application and the granularity of your time_stamp this may not be a valid assumption. If you need to deal with ties of time_stamp for a given user, you'd need to extend one of the answers given above.

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

To write this in one query would require another nested sub-query - things will start getting more messy and performance may suffer.

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

I would have loved to have added this as a comment but I don't yet have 50 reputation so sorry for posting as a new answer!

我很想把这句话加在评论里,但是我还没有50个声誉,所以很抱歉我把它作为一个新的回复。

#5


2  

Can't post comments yet, but @Cristi S's answer works a treat for me.

不能发表评论,但@Cristi S回答我的治疗工作。

In my scenario, I needed to keep only the most recent 3 records in Lowest_Offers for all product_ids.

在我的场景中,我只需要在Lowest_Offers中保存所有product_id的最近3条记录。

Need to rework his SQL to delete - thought that this would be ok, but syntax is wrong.

需要重新修改他的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;

#6


0  

I've been using this because I'm returning results from another table. Though I'm trying to avoid the nested join if it helps w/ one less step. Oh well. It returns the same thing.

我使用这个是因为我要返回另一个表的结果。虽然我试图避免嵌套连接,如果它有助于减少一步。哦。它返回相同的东西。

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

#1


90  

Try this:

试试这个:

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

#2


29  

Nice elegant solution with ROW_NUMBER window function (supported by PostgreSQL - see in SQL Fiddle):

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

#3


7  

Something like this:

是这样的:

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

should do it.

应该这样做。

#4


3  

Both of the above answers assume that you only have one row for each user and time_stamp. Depending on the application and the granularity of your time_stamp this may not be a valid assumption. If you need to deal with ties of time_stamp for a given user, you'd need to extend one of the answers given above.

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

To write this in one query would require another nested sub-query - things will start getting more messy and performance may suffer.

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

I would have loved to have added this as a comment but I don't yet have 50 reputation so sorry for posting as a new answer!

我很想把这句话加在评论里,但是我还没有50个声誉,所以很抱歉我把它作为一个新的回复。

#5


2  

Can't post comments yet, but @Cristi S's answer works a treat for me.

不能发表评论,但@Cristi S回答我的治疗工作。

In my scenario, I needed to keep only the most recent 3 records in Lowest_Offers for all product_ids.

在我的场景中,我只需要在Lowest_Offers中保存所有product_id的最近3条记录。

Need to rework his SQL to delete - thought that this would be ok, but syntax is wrong.

需要重新修改他的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;

#6


0  

I've been using this because I'm returning results from another table. Though I'm trying to avoid the nested join if it helps w/ one less step. Oh well. It returns the same thing.

我使用这个是因为我要返回另一个表的结果。虽然我试图避免嵌套连接,如果它有助于减少一步。哦。它返回相同的东西。

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