查找每个组件的最新记录 MySQL

Find most recent record MySQL per component

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

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

通常我会使用这个问题的公认答案所描述的解决方案: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。

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

它不会提供正确的结果,因为 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;

可以使用变量来模拟

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

window函数:

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

我最终通过以下查询解决了我的问题:

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 上的复合索引和时间戳,查询是即时的。