如何解决如何在 TimeScaleDB、PostgreSQL 的 time_bucket_gapfill() 中使用 AVG() 和 GROUP BY?
我在我的 Postgresql 中使用 TimescaleDB,我有以下两个表:
windows_log
| windows_log_id | timestamp | computer_id | log_count |
------------------------------------------------------------------
| 1 | 2021-01-01 00:01:02 | 382 | 30 |
| 2 | 2021-01-02 14:59:55 | 382 | 20 |
| 3 | 2021-01-02 19:08:24 | 382 | 20 |
| 4 | 2021-01-03 13:05:36 | 382 | 10 |
| 5 | 2021-01-03 22:21:14 | 382 | 40 |
windows_reliability_score
| computer_id (FK) | timestamp | reliability_score |
--------------------------------------------------------------
| 382 | 2021-01-01 22:21:14 | 6 |
| 382 | 2021-01-01 22:21:14 | 6 |
| 382 | 2021-01-01 22:21:14 | 6 |
| 382 | 2021-01-02 22:21:14 | 1 |
| 382 | 2021-01-02 22:21:14 | 3 |
| 382 | 2021-01-03 22:21:14 | 7 |
| 382 | 2021-01-03 22:21:14 | 8 |
| 382 | 2021-01-03 22:21:14 | 9 |
注意:在两个表中都是在时间戳列(hypertable)上建立索引
所以我试图获得每个时间段的平均可靠性分数,但它只是给了我所有内容的平均值,而不是每个特定时间段的平均值......
这是我的查询:
SELECT time_bucket_gapfill(CAST(1 * INTERVAL '1 day' AS INTERVAL),wl.timestamp) AS timestamp,COALESCE(SUM(log_count),0) AS log_count,AVG(reliability_score) AS reliability_score
FROM windows_log wl
JOIN reliability_score USING (computer_id)
WHERE wl.time >= '2021-01-01 00:00:00.0' AND wl.time < '2021-01-04 00:00:00.0'
GROUP BY timestamp
ORDER BY timestamp asc
这是我要找的结果:
| timestamp | log_count | reliability_score |
-------------------------------------------------------
| 2021-01-01 00:00:00 | 30 | 6 |
| 2021-01-02 00:00:00 | 20 | 2 |
| 2021-01-03 00:00:00 | 20 | 8 |
但这就是我得到的:
| timestamp | log_count | reliability_score |
-------------------------------------------------------
| 2021-01-01 00:00:00 | 30 | 5.75 |
| 2021-01-02 00:00:00 | 20 | 5.75 |
| 2021-01-03 00:00:00 | 20 | 5.75 |
解决方法
主要问题是连接条件在列 computer_id
上,其中两个表具有相同的值 382
。因此,表 windows_log
中的每一列都将与表 reliability_score
中的每一列(所有行的笛卡尔积)连接起来。此外,分组是在列 timestamp
上完成的,这是不明确的,很可能从 timestamp
解析为 windows_log
。这导致平均值将使用 reliability_score
的每个时间戳值的所有值,并解释不希望的结果。
在SELECT
documentation中的windows_log
描述中解释了有利于内部列(即表列)的解决歧义:
如果出现歧义,GROUP BY 名称将被解释为输入列名称而不是输出列名称。
为了避免分组,包括所有匹配计算机 id 的行,GROUP BY
可用于分组。这将允许将 windows_log_id
带入查询结果。如果希望保留输出名称 log_count
,GROUP BY 应使用对位置的引用。例如:
timestamp
对于 ORDER BY 这不是问题,因为使用了输出名称。来自同一个文档:
如果 ORDER BY 表达式是一个匹配输出列名和输入列名的简单名称,ORDER BY 会将其解释为输出列名。
,鉴于我们可以从您的示例中收集到的信息,没有简单的方法可以使用给定的函数在这两个表之间进行连接并获得您想要的结果。所呈现的模式只是让这变得困难。
如果这确实是您的数据/架构的样子,那么一种解决方案是使用多个 CTE 从每个不同的表中获取两个值,然后根据存储桶和计算机进行连接。
WITH wrs AS (
SELECT time_bucket_gapfill('1 day',timestamp) AS bucket,computer_id,AVG(reliability_score) AS reliability_score
FROM windows_reliability_score
WHERE timestamp >= '2021-01-01 00:00:00.0' AND timestamp < '2021-01-04 00:00:00.0'
GROUP BY 1,2
),wl AS (
SELECT time_bucket_gapfill('1 day',wl.timestamp) bucket,wl.computer_id,sum(log_count) total_logs
FROM windows_log wl
WHERE timestamp >= '2021-01-01 00:00:00.0' AND timestamp < '2021-01-04 00:00:00.0'
GROUP BY 1,2
)
SELECT wrs.bucket,wrs.computer_id,reliability_score,total_logs
FROM wrs LEFT JOIN wl ON wrs.bucket = wl.bucket AND wrs.computer_id = wl.computer_id;
过滤必须在内部应用于每个查询,因为可能不会发生对外部查询的下推,因此您将在应用日期过滤器之前扫描整个超表(我假设不是您想要的)。
我尝试快速重新创建您的示例架构,因此如果我在某处弄错了名称,我深表歉意。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。