我正在尝试进行高级分析查询以驱动Web应用程序。我在TimescaleDB中使用Hapi,Objection,Knex和Postgres。对于典型的关系查询,一切都很好。但是,我无法弄清楚如何执行该聚合查询,该查询涉及与从Postgres的generate_series
生成的匿名表联接。我不得不求助于编写原始SQL,而不是使用Objection / Knex查询生成器。我正在使用Postgres的一些内置函数,以及Timescale的time_bucket
。 time_bucket
本质上基于参数中指定的间隔创建数据汇总。请查看此链接,以获取有关我尝试做的Gap Filling的更多信息。
这是查询,它使用对象模型上的raw方法工作。我相信像这样进行字符串内插会导致潜在的SQL注入。但是,我希望将其转换为Objection / Knex使用的查询生成器方法,以便使用更多的JavaScript而不是SQL来解决SQL注入问题。
let errorHistorgram = await Errors
.raw(`SELECT period AS daily, coalesce(count,0) AS count
FROM generate_series(date '${startTS}', date '${today}', interval '1d') AS period
LEFT JOIN (
SELECT time_bucket('1d',timestamp)::date AS date, count(timestamp)
FROM my_error_table
WHERE severity = 'HIGH'
AND timestamp >= '${startTS}' AND timestamp < '${today}'
AND device_id = ${deviceId}
GROUP BY date
) t ON t.date = period;`)
.debug();
我曾用Objection / Knex进行过几次尝试。这是我最成功地制作此查询的尝试。但是,我认为where子句的位置不正确。
let errorHistorgram = await Errors
.query()
.select(raw(`time_bucket('1 day', timestamp) AS daily, count(timestamp)`))
.where('device_id', deviceId)
.andWhere('timestamp', '>', startTS)
.andWhere('severity', 'HIGH')
.leftJoin(`generate_series(date ${startTS}, date ${today}, interval 1d) AS series`, 'series.date', 'my_error_table.timestamp')
.debug();
使用.debug()
,我可以看到查询的输出,该输出显示在下面。
select time_bucket('1 day', timestamp) AS daily, count(timestamp)
from my_error_table
left join "generate_series(date 2018-11-08T15:35:33"."050Z, date 2018-11-15T15:35:33"."133Z, interval 1d)" as "series"
on "series"."date" = my_error_table."timestamp"
where "device_id" = ? and "timestamp" > ? and "severity" = ?'
我们会提供任何帮助,因为我没有使用异议来做,因此也找不到任何文档。
我可以用Objection执行查询。但是,我得到一个空数组作为结果。与上面我编写的原始SQL查询不同(确实给了我预期的结果),我只是得到一个空数组作为查询构建器的输出。关于我在做什么错的任何想法。我试图将连接翻转为正确的连接,但是没有运气。
let errorHistorgram = await Errors
.query()
.select(raw(`time_bucket('1 day', timestamp) AS daily, count(timestamp)`))
.where('device_id', deviceId)
.andWhere('timestamp', '>', startTS)
.andWhere('severity', 'HIGH')
.groupBy('timestamp')
.rightJoin(raw(`generate_series(date '${startTS}', date '${today}', interval '1d') AS series`), 'series.date', 'my_error_table.timestamp')
.debug();
已附上Debug的SQL输出。
select time_bucket('1 day', timestamp) AS daily, count(timestamp)
from my_errors_table
right join generate_series(date '2018-11-08', date '2018-11-15', interval '1d') AS series
on series = my_errors_table.timestamp
where device_id = ? and timestamp > ? and severity = ?
group by timestamp
答案 0 :(得分:0)
Timescale发布了一项名为Time Bucket Gapfill的新功能。这使此操作变得容易得多,因为您无需再与generate_series
进行左连接来填补空白。
我提供了一个示例,该示例说明了如何使用名为Errors
的ObjectionJS模型来实现此功能。 time_bucket_gapfill
函数的输入是存储区大小,时间戳列名称,startTS和endTS。值区大小变量应为带有""
(不是单引号)的字符串,该字符串与值区大小相对应(例如:"10 seconds"
,"30 minutes"
,"1 hour"
,{{1} }。 "1 day"
和startTS
应该是ISO日期字符串。第二个select语句需要stopTS
,以便在存储桶中不包含任何数据的情况下生成的存储桶将输出0。根据您在COALESCE
语句中提供的汇总SQL函数,存储桶需要group by
来正确汇总数据。
select