PostgreSQL按5分钟间隔分组并筛选特定行的SQL查询需求
原始数据表
| id | quantity | timestamp | value | flag |
|---|---|---|---|---|
| 1 | temperature | some TS | 30 | 0 |
| 2 | pressure | some TS | 10 | 0 |
| 3 | temperature | some TS | 30 | 3 |
| 4 | pressure | some TS | 10 | 1 |
| 5 | temperature | some TS | 30 | 0 |
| 6 | pressure | some TS | 10 | 2 |
| 7 | temperature | some TS | 30 | 3 |
| 8 | pressure | some TS | 10 | 0 |
| 9 | temperature | some TS | 30 | 3 |
| 10 | pressure | some TS | 10 | 0 |
分组规则
- 按5分钟时间间隔 + quantity分组
- 规则1:区间内所有flag为0/1/2时,value取平均值;flag取出现次数最多的,次数相同则取最大的flag
- 规则2:区间内存在flag=3但多数行是0/1/2时,仅计算0/1/2行的value平均值,flag按规则1从这些有效行计算
- 规则3:区间内多数行flag为3时,计算所有行的value平均值,flag设为3
解决方案(以PostgreSQL为例)
WITH grouped_base AS ( -- 按5分钟间隔和quantity分组,计算基础统计值 SELECT quantity, -- 生成5分钟时间区间起始点 date_trunc('minute', timestamp) - INTERVAL '1 minute' * (EXTRACT(minute FROM timestamp)::int % 5) AS interval_start, COUNT(*) AS total_rows, SUM(CASE WHEN flag = 3 THEN 1 ELSE 0 END) AS flag3_count, -- 0/1/2行的平均值 AVG(CASE WHEN flag IN (0,1,2) THEN value END) AS valid_avg_value, -- 所有行的平均值 AVG(value) AS all_avg_value, -- 收集有效flag用于后续统计 array_agg(CASE WHEN flag IN (0,1,2) THEN flag END) AS valid_flags FROM your_table_name GROUP BY quantity, date_trunc('minute', timestamp) - INTERVAL '1 minute' * (EXTRACT(minute FROM timestamp)::int % 5) ), flag_stats AS ( -- 统计有效flag中出现次数最多、最大的那个 SELECT quantity, interval_start, total_rows, flag3_count, valid_avg_value, all_avg_value, (SELECT flag FROM unnest(valid_flags) AS flag GROUP BY flag ORDER BY COUNT(*) DESC, flag DESC LIMIT 1) AS dominant_valid_flag FROM grouped_base ) -- 按规则输出最终结果 SELECT quantity, interval_start, CASE WHEN flag3_count > total_rows / 2 THEN all_avg_value ELSE valid_avg_value END AS avg_value, CASE WHEN flag3_count > total_rows / 2 THEN 3 ELSE dominant_valid_flag END AS final_flag FROM flag_stats ORDER BY quantity, interval_start;
关键细节说明
- 时间分组适配:不同数据库的5分钟区间生成逻辑略有差异:
- MySQL:
DATE_FORMAT(timestamp, '%Y-%m-%d %H:%i:00') - INTERVAL (MINUTE(timestamp) % 5) MINUTE - SQL Server:
DATEADD(minute, DATEDIFF(minute, 0, timestamp) / 5 * 5, 0)
- MySQL:
- flag统计逻辑:通过
array_agg收集有效flag后,子查询按出现次数降序、flag值降序排序,确保次数相同时取最大的flag - 规则判断:通过对比
flag3_count和总记录数的一半,区分触发规则2还是规则3,规则1则自动覆盖在非规则3的分支里
内容的提问来源于stack exchange,提问作者vikasraj789
相关产品推荐
相关产品推荐

