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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1140064/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 02:51:22  来源:igfitidea点击:

SQL query to get most recent row for each instance of a given key

sqlpostgresqlgreatest-n-per-group

提问by alanc10n

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。

回答by Chris Nielsen

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

回答by Cristi S.

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;

回答by Kim Gr?sman

Something like this:

像这样的东西:

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

should do it.

应该这样做。

回答by user2323503

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 名声望,因此很抱歉将其作为新答案发布!

回答by err1

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;

回答by jawz101

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