JOOQ使用timeBucketGapfill求平均值时报错如何解决?
问题原因
这个报错是TimescaleDB对time_bucket_gapfill函数的语法强制限制:该函数必须直接出现在group by子句的顶层,不能用select语句里的别名替代。
你之前的写法里,groupBy传入的是已经通过asField(TIME)绑定了别名的字段,JOOQ生成SQL时会将group by子句渲染为group by "time",而非完整的time_bucket_gapfill函数调用,因此触发了数据库的校验报错。
解决方案
核心修改点有3个:
groupBy直接传入未绑定别名的TimeBucketGapfill6函数实例,保证生成的SQL里group by后是完整的函数调用- 要用上一个观测值填充空桶的平均值,需要用
locf函数包裹聚合逻辑 - 建议将
start和end参数同时传入time_bucket_gapfill函数:TimescaleDB需要通过这两个参数确定补全间隙的边界,你同时在where子句保留时间范围条件不会影响性能,数据库优化器会自动做谓词下推
另外你代码里有个笔误:TIME.SERIES.ID.eq(id)应该改为TIME_SERIES.ID.eq(id),还有之前的桶宽参数用了全年时间跨度作为分桶宽度,只会生成一个时间桶,需要改成你实际需要的分桶粒度(比如1小时、1天)。
修正后代码示例
public static final String TIME = "time"; public static final String VALUE = "value"; OffsetDateTime start = OffsetDateTime.parse("2020-01-01T00:00:00Z"); OffsetDateTime end = OffsetDateTime.parse("2020-12-31T23:00:00Z"); // 构造gapfill函数实例,暂时不绑定别名 TimeBucketGapfill6 timeBucketGapfill = new TimeBucketGapfill6(); // 按实际需求设置分桶粒度,示例为按1小时分桶 timeBucketGapfill.setBucketWidth(YearToSecond.valueOf(Duration.ofHours(1))); timeBucketGapfill.setTs(TIME_SERIES.TIME); // 传入时间范围给gapfill函数用于生成间隙 timeBucketGapfill.setStart(start); timeBucketGapfill.setEnd(end); dsl.select( // select语句里再绑定别名 timeBucketGapfill.asField(TIME), // 用locf包裹聚合函数,自动用上一个非空值填充空桶 DSL.locf(DSL.avg(TIME_SERIES.VALUE)).as(VALUE) ) .from(TIME_SERIES) .where(TIME_SERIES.TIME.between(start, end)) // 修正笔误 .and(TIME_SERIES.ID.eq(id)) // 关键:groupBy传入原始函数实例,不要用带别名的字段 .groupBy(timeBucketGapfill) .fetch();
内容的提问来源于stack exchange,提问作者AiR
相关产品推荐
相关产品推荐

