编写Cronjob分析数据库flags表,如何基于两列唯一组合取最新行?
解决Cronjob中Flags表按def-price组合取最新行的需求
针对你要编写的Cronjob需求——从flags表中为每个def+price的唯一组合保留最新行(用IFNULL(time_resolved, time_flagged)判定时间先后),同时自动排除无对应行的组合、确保无重复,我给你两种可行的解决方案,适配不同的数据库版本:
推荐方案:使用窗口函数(MySQL 8+、PostgreSQL、SQL Server等现代数据库)
这种方式逻辑清晰,性能也更优,是处理分组取最新记录的标准做法:
实现思路
- 首先生成统一的时间字段
record_time:用IFNULL(time_resolved, time_flagged)把两种时间字段合并,优先取已处理的time_resolved,未处理的用time_flagged - 用
ROW_NUMBER()窗口函数按def和price分组,每组内按record_time降序排序,这样最新的记录会被标记为row_num = 1 - 最后过滤出标记为1的记录,就是每个组合的唯一最新行
完整SQL代码
SELECT * FROM ( SELECT *, -- 生成统一的判定时间 IFNULL(`time_resolved`, `time_flagged`) AS `record_time`, -- 按def+price分组,每组内按时间降序编号 ROW_NUMBER() OVER ( PARTITION BY `def`, `price` ORDER BY IFNULL(`time_resolved`, `time_flagged`) DESC ) AS `row_num` FROM `flags` ) AS flagged_data WHERE `row_num` = 1;
效果说明
- 自动忽略无对应行的def-price组合(因为分组时根本不会生成这些组合的记录)
- 像你提到的行1和行4属于同一def-price组合的情况,行4的
record_time更新,会被标记为row_num=1,行1会被过滤掉,完全符合你的“覆盖”需求
兼容旧版本数据库(比如MySQL 5.x,不支持窗口函数)
如果你的数据库版本较低,无法使用窗口函数,可以用子查询关联的方式实现:
实现思路
- 先分组计算每个def-price组合的最新时间
latest_time - 再关联原表,找出对应组合中时间等于
latest_time的记录
完整SQL代码
SELECT f1.* FROM `flags` f1 INNER JOIN ( SELECT `def`, `price`, -- 计算每个组合的最新时间 MAX(IFNULL(`time_resolved`, `time_flagged`)) AS `latest_time` FROM `flags` GROUP BY `def`, `price` ) f2 ON f1.`def` = f2.`def` AND f1.`price` = f2.`price` AND IFNULL(f1.`time_resolved`, f1.`time_flagged`) = f2.`latest_time`;
注意事项
如果同一def-price组合有两条记录的record_time完全相同,这个查询会返回多条。如果需要确保只取一条,可以在子查询或关联条件中加入额外的排序字段(比如主键ID降序),比如修改子查询为:
SELECT `def`, `price`, MAX(CONCAT(IFNULL(`time_resolved`, `time_flagged`), '_', `id`)) AS `latest_key` FROM `flags` GROUP BY `def`, `price`
然后关联时拆分latest_key来匹配时间和最大ID,确保唯一。
最后把这个SQL集成到你的Cronjob中即可,比如通过crontab调度脚本执行,或者在你的任务调度工具中配置定时执行这个查询,再进行后续的分析处理。
内容的提问来源于stack exchange,提问作者Adam Rezich
相关产品推荐
相关产品推荐

