diff --git a/internal/dao/sensor.go b/internal/dao/sensor.go index 3468a83..b5067c5 100644 --- a/internal/dao/sensor.go +++ b/internal/dao/sensor.go @@ -42,67 +42,56 @@ func (dao *SensorDAO) Insert(data *model.SensorData) error { // 获取聚合数据 func (dao *SensorDAO) GetAggregatedData(start, end time.Time, interval string) ([]model.AggregatedData, error) { - var query string + // 参数化时间间隔 + var intervalMinutes int + var timeFormat string + switch interval { case "5min": - query = ` - SELECT - DATE_FORMAT( - FROM_UNIXTIME( - FLOOR(UNIX_TIMESTAMP(timestamp)/(5*60))*(5*60) - ), - '%Y-%m-%dT%H:%i:00' - ) as ts, - ROUND(AVG(temperature)/10, 1) as avg_temp, - MAX(rainfall) - MIN(rainfall) as rainfall, - ROUND(AVG(humidity)/10, 1) as avg_humidity, - ROUND(AVG(wind_speed)/10, 1) as avg_wind_speed - FROM sensor_data - WHERE timestamp BETWEEN ? AND ? - GROUP BY FLOOR(UNIX_TIMESTAMP(timestamp)/(5*60)) - ORDER BY ts DESC - ` + intervalMinutes = 5 + timeFormat = "%Y-%m-%dT%H:%i:00" case "30min": - query = ` - SELECT - DATE_FORMAT( - FROM_UNIXTIME( - FLOOR(UNIX_TIMESTAMP(timestamp)/(30*60))*(30*60) - ), - '%Y-%m-%dT%H:%i:00' - ) as ts, - ROUND(AVG(temperature)/10, 1) as avg_temp, - MAX(rainfall) - MIN(rainfall) as rainfall, - ROUND(AVG(humidity)/10, 1) as avg_humidity, - ROUND(AVG(wind_speed)/10, 1) as avg_wind_speed - FROM sensor_data - WHERE timestamp BETWEEN ? AND ? - GROUP BY FLOOR(UNIX_TIMESTAMP(timestamp)/(30*60)) - ORDER BY ts DESC - ` + intervalMinutes = 30 + timeFormat = "%Y-%m-%dT%H:%i:00" default: // 1hour - query = ` - SELECT - DATE_FORMAT( - FROM_UNIXTIME( - FLOOR(UNIX_TIMESTAMP(timestamp)/3600)*3600 - ), - '%Y-%m-%dT%H:00:00' - ) as ts, - ROUND(AVG(temperature)/10, 1) as avg_temp, - MAX(rainfall) - MIN(rainfall) as rainfall, - ROUND(AVG(humidity)/10, 1) as avg_humidity, - ROUND(AVG(wind_speed)/10, 1) as avg_wind_speed - FROM sensor_data - WHERE timestamp BETWEEN ? AND ? - GROUP BY FLOOR(UNIX_TIMESTAMP(timestamp)/3600) - ORDER BY ts DESC - ` + intervalMinutes = 60 + timeFormat = "%Y-%m-%dT%H:00:00" } - rows, err := dao.db.Query(query, start, end) + // 计算秒数 + intervalSeconds := intervalMinutes * 60 + + // 构建通用查询 + query := ` + SELECT + DATE_FORMAT( + FROM_UNIXTIME( + FLOOR(UNIX_TIMESTAMP(timestamp)/?)*? + ), + ? + ) as ts, + ROUND(AVG(temperature)/10, 1) as avg_temp, + MAX(rainfall) - MIN(rainfall) as rainfall, + ROUND(AVG(humidity)/10, 1) as avg_humidity, + ROUND(AVG(wind_speed)/10, 1) as avg_wind_speed + FROM sensor_data + WHERE timestamp BETWEEN ? AND ? + GROUP BY FLOOR(UNIX_TIMESTAMP(timestamp)/?) + ORDER BY ts DESC + ` + + // 执行查询 + rows, err := dao.db.Query( + query, + intervalSeconds, intervalSeconds, // 用于FROM_UNIXTIME参数 + timeFormat, // DATE_FORMAT格式 + start, end, // 时间范围 + intervalSeconds, // GROUP BY参数 + ) + if err != nil { - logger.Logger.Printf("查询聚合数据失败: %v", err) + logger.Logger.Printf("查询聚合数据失败: %v (间隔=%s, 开始=%s, 结束=%s)", + err, interval, start.Format(time.RFC3339), end.Format(time.RFC3339)) return nil, err } defer rows.Close() @@ -117,14 +106,23 @@ func (dao *SensorDAO) GetAggregatedData(start, end time.Time, interval string) ( logger.Logger.Printf("扫描数据行失败: %v", err) continue } + // 解析ISO格式的时间字符串 data.Timestamp, err = time.Parse("2006-01-02T15:04:05", tsStr) if err != nil { - logger.Logger.Printf("解析时间失败: %v", err) + logger.Logger.Printf("解析时间失败: %v, 原始字符串: %s", err, tsStr) continue } + result = append(result, data) } + // 检查是否有游标错误 + if err = rows.Err(); err != nil { + logger.Logger.Printf("查询游标错误: %v", err) + return nil, err + } + + logger.Logger.Printf("聚合查询成功: 返回%d条记录 (间隔=%s)", len(result), interval) return result, nil }