0

我在我的 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)上建立索引

所以我试图获得每个时间桶的平均reliability_score,但它只是给了我所有东西的平均值,而不是每个特定桶的平均值......

这是我的查询:

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       |
4

2 回答 2

1

鉴于我们可以从您的示例中收集到的信息,没有简单的方法可以使用给定的函数在这两个表之间进行连接并获得您想要的结果。所呈现的模式只是让这变得困难。

如果这确实是您的数据/模式的样子,那么一种解决方案是使用多个 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;

过滤必须在内部应用于每个查询,因为可能不会发生外部查询的下推,因此您将在应用日期过滤器之前扫描整个超表(不是您想要的我假设的)。

我试图快速重新创建您的示例模式,所以如果我在某处命名错误,我深表歉意。

于 2021-07-20T01:33:37.853 回答
0

主要问题是连接代码在列上computer_id,其中两个表具有相同的值382。因此,表中的每一列windows_log都将与表中的每一列连接reliability_score(所有行的笛卡尔积)。此外,分组是在 column 上完成的timestamp,这是模棱两可的,很可能被解析为timestampfrom windows_log。这导致平均值将使用reliability_score时间戳的每个值的所有值的结果,windows_log并解释了不希望的结果。

在文档GROUP BY中的描述中解释了解决有利于内部列(即表格列)的摸索歧义的解决方法:SELECT

如果有歧义,GROUP BY 名称将被解释为输入列名称而不是输出列名称。

为避免包含与计算机 ID 匹配的所有行的组,windows_log_id可用于分组。这将允许带来log_count查询结果。如果希望保留输出名称timestamp,则 GROUP BY 应该使用对位置的引用。例如:

SELECT time_bucket_gapfill('1 day'::INTERVAL, rs.timestamp) AS timestamp, 
AVG(reliability_score) AS reliability_score,
log_count
FROM windows_log wl
JOIN reliability_score rs USING (computer_id)
WHERE rs.timestamp >= '2021-01-01 00:00:00.0' AND rs.timestamp < '2021-01-04 00:00:00.0'
GROUP BY 1, windows_log_id, log_count
ORDER BY timestamp asc

对于 ORDER BY,这不是问题,因为使用了输出名称。来自同一个文档:

如果 ORDER BY 表达式是与输出列名和输入列名都匹配的简单名称,则 ORDER BY 会将其解释为输出列名。

于 2021-07-13T20:28:58.810 回答