PostgreSQL实现按时间倒序筛选特定START关联数据的查询
解决PostgreSQL中按特定规则筛选日志行的问题
针对需求,我们可以通过PostgreSQL的窗口函数实现分组筛选,具体如下:
需求明确
从包含ID、DT(日期时间)、PS(打印语句)的表中,按以下规则提取数据:
- 按
DT降序排序(最新记录在前) - 收集连续的
PS包含data的行,直到遇到含START的行 - 若遇到的
START行内容为START:123456(不区分大小写),则保留收集的data行及该START行 - 重复上述逻辑处理后续行
实现SQL
假设表名为print_log,列名分别为id、dt(timestamp类型)、ps(text类型),执行以下查询:
WITH sorted_data AS ( SELECT id, dt, ps, -- 生成分组ID:每遇到含START的记录,分组ID递增 SUM(CASE WHEN ps ILIKE '%START%' THEN 1 ELSE 0 END) OVER (ORDER BY dt DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS group_id FROM print_log ), group_validation AS ( SELECT group_id, -- 获取每个分组的结尾START记录内容 MAX(CASE WHEN ps ILIKE '%START%' THEN ps END) AS end_start_content FROM sorted_data GROUP BY group_id ) -- 筛选出结尾为START:123456的分组内所有记录 SELECT sd.id, sd.dt, sd.ps FROM sorted_data sd JOIN group_validation gv ON sd.group_id = gv.group_id WHERE gv.end_start_content = 'START:123456' ORDER BY sd.dt DESC;
逻辑解释
sorted_dataCTE:先按DT降序排序所有记录,用窗口函数SUM生成分组ID。每遇到含START的记录,分组ID加1,确保连续的data记录归为同一分组,直到下一个START记录出现。group_validationCTE:针对每个分组,提取其结尾的START记录内容(无START记录则为NULL)。- 最终查询:仅保留结尾
START内容为START:123456的分组内所有记录,按DT降序输出。
示例验证
用提供的示例数据测试,查询返回结果如下,与预期完全一致:
id | dt | ps ----+---------------------+------------------ 1 | 2022-10-05 16:03:50 | 'data' 2 | 2022-10-05 16:03:49 | 'Start:123456' 5 | 2022-10-05 16:03:46 | 'data' 6 | 2022-10-05 16:03:45 | 'data' 7 | 2022-10-05 16:03:44 | 'data' 8 | 2022-10-05 16:03:43 | 'START:123456'
性能优化建议
该方案用窗口函数处理分组,PostgreSQL优化效果较好,处理10万行数据无压力。建议给dt列创建索引提升排序性能:
CREATE INDEX idx_print_log_dt ON print_log(dt DESC);
内容的提问来源于stack exchange,提问作者Denver_Colorado
相关产品推荐
相关产品推荐

