【问题标题】:SQL query to get most recent row for each instance of a given keySQL查询以获取给定键的每个实例的最新行
【发布时间】: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。

【问题讨论】:

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


    【解决方案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 引擎不一样的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 2021-01-10
    • 1970-01-01
    • 2020-08-31
    • 2021-10-07
    • 2011-01-25
    • 2023-01-22
    相关资源
    最近更新 更多