【问题标题】:Find most recent record MySQL per component查找每个组件的最新记录 MySQL
【发布时间】:2015-06-23 05:55:06
【问题描述】:

我有一个定期报告状态的组件列表。

我想编写一个查询来查找按组件分组的最新状态列表。

通常我会使用这个问题的公认答案所描述的解决方案:MySQL order by before group by

但是,每秒可能会报告多个状态,因此无法保证我会检索到最新的。因此,我想找到具有最新时间戳的状态,并且在重复时间戳的情况下,找到具有最高 PK 的状态。

理想情况下,我希望有如下查询:

SELECT *
FROM component_status 
ORDER BY component_status.timestamp DESC, component_status.component_status_id DESC
GROUP BY component_status.component_id;

但是您不能在 ORDER BY 之后执行 GROUP BY。

有没有人遇到过类似的问题并找到了解决方案?

【问题讨论】:

  • 我看不出您的问题与所引用的问题有何不同。
  • @Strawberry 引用的帖子使用 single 列上的聚合来获取最新记录。在这个问题中,最近的记录由 两个 列确定。
  • @GiorgosBetsos 当然可以,但原理还是一样。

标签: mysql sql group-by sql-order-by


【解决方案1】:

可以使用变量来模拟

 ROW_NUMBER() OVER (PARTITION BY component_id 
                    ORDER BY `timestamp` DESC, component_status_id DESC)

窗口函数:

SELECT component_id, component_status_id, `timestamp`
FROM (
SELECT component_id, component_status_id, `timestamp`, 
       @row_number:= 
          IF (@cid <> component_id,
             IF (@cid := component_id, 1, 1),
             IF (@cid := component_id, @row_number + 1, @row_number + 1)) AS rn   
FROM component_status
CROSS JOIN (SELECT @row_number:= 0, @cid := -1) vars
ORDER BY `timestamp` DESC, component_status_id DESC ) t
WHERE rn = 1

外部查询中的rn=1 根据component_id 选择最近的记录。如果有两个或多个记录具有相同的timestamp,则将选择具有最大component_status_id 的记录。

Demo here

【讨论】:

  • 这看起来很有希望!我会试一试,然后告诉你进展如何。
【解决方案2】:

它不会提供正确的结果,因为 order by 在 group by 之后工作,为此您可以先在子查询中获取 order by 结果,然后您可以将它们分组。

例如-

select field1, field2 from (SELECT field1,field2,...,component_status.component_id  
FROM component_status 
ORDER BY component_status.timestamp DESC, component_status.component_status_id DESC) a 
GROUP BY a.component_id;

【讨论】:

  • 我尝试过这样的事情,但有数百万条记录,而且速度极慢且效率低下(即使有索引)。
  • 是的,如果表很大,它会很慢,如果它是一次性活动,那么你必须忍受它,但如果在生产中需要它,那么应该有一些数据过滤来优化它而不是全表数据扫描。
【解决方案3】:

我最终使用以下查询来解决我的问题:

SELECT 
    component_status.*
FROM
    component_status
JOIN
    (SELECT 
        MAX(component_status_id) AS component_status_id
    FROM
        component_status
    JOIN 
        (SELECT 
            MAX(timestamp) AS timestamp, component_id
        FROM
            component_status
        WHERE
            timestamp <= NOW()
        GROUP BY component_id) AS most_recent_status 
    USING (component_id)
    WHERE component_status.timestamp = most_recent_status.timestamp
    GROUP BY component_id) AS most_recent_status 
USING (component_status_id)

使用 component_id 和时间戳上的复合索引,查询是即时的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-24
    • 2018-09-07
    • 1970-01-01
    • 2021-10-04
    • 2016-08-22
    • 1970-01-01
    • 1970-01-01
    • 2021-11-22
    相关资源
    最近更新 更多