SQL查询以获取给定键的每个实例的最新行
Posted
技术标签:
【中文标题】SQL查询以获取给定键的每个实例的最新行【英文标题】:SQL query to get most recent row for each instance of a given key 【发布时间】:2010-11-11 12:32:14 【问题描述】:我正在尝试从一个表中获取 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
我希望查询的输出是:
jerry | 5.6.6.7 | 12
ted | 8.8.8.8 | 30
我可以在单个 sql 查询中执行此操作吗?如果重要,DBMS 是 Postgresql。
【问题讨论】:
【参考方案1】:还不能发布 cmets,但 @Cristi S 的回答对我来说是一种享受。
在我的场景中,我只需要在 Lowest_Offers 中为所有 product_id 保留最近的 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;
【讨论】:
更正 SQL:从 Lowest_Offer 中删除 id in (SELECT id FROM (SELECT product_id, id, date_checked, ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY date_checked DESC) rn FROM Lowest_Offer) tmp WHERE rn> 3) 我认为这需要一个 desc 索引而不是时间戳【参考方案2】:带有 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;
【讨论】:
这是最好的答案,因为它不涉及嵌套查询的连接。唯一的问题是它需要在密钥中包含 [ip] 以及每个问题的用户名。 这是最高效的解决方案。使用 POSTGRES 解释分析工具尝试了这些解决方案,这是最好的。优秀的代码【参考方案3】:我一直在使用它,因为我要从另一个表返回结果。虽然我试图避免嵌套连接,如果它有助于少一步。那好吧。它返回相同的东西。
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
【讨论】:
我认为这是上述用户响应的答案【参考方案4】:以上两个答案都假设每个用户和时间戳只有一行。根据应用程序和 time_stamp 的粒度,这可能不是一个有效的假设。如果您需要处理给定用户的 time_stamp 关系,则需要扩展上面给出的答案之一。
在一个查询中写这个需要另一个嵌套的子查询 - 事情会开始变得更加混乱,性能可能会受到影响。
我很想将此作为评论添加,但我还没有 50 名声望,所以很抱歉作为新答案发布!
【讨论】:
“以上都...”不是开始回答的好方法。我怎么知道上面的答案是否是您所指的答案?答案可以根据分数以不同的顺序出现。 Rob,我不认为你在告诉他一些他不知道的事情。他不能发表评论,他所指的答案显然有缺陷。更重要的是传播知识还是批评文本的放置位置?【参考方案5】:类似这样的:
select *
from User U1
where time_stamp = (
select max(time_stamp)
from User
where username = U1.username)
应该这样做。
【讨论】:
如果time_stamp
是唯一的并且您不能假设,那将起作用。【参考方案6】:
试试这个:
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
【讨论】:
我在正确的轨道上,但我无法完全正确地加入。这成功了。谢谢! 这在 SQL Server 中有效吗?在类似的数据上尝试了完全相同的事情,但我得到了每个“ip”的一行以及最近的时间戳。 针对 HANA 表使用,这会产生预期为 1 的多行。 HANA 有很多与大多数流行的 SQL 引擎不一样的东西。以上是关于SQL查询以获取给定键的每个实例的最新行的主要内容,如果未能解决你的问题,请参考以下文章