计算一个值的变化与 TimescaleDB 中的最后一个读数
Calculating the change of a value versus the last reading in TimescaleDB
我在 TimescaleDB 中存储了大量关于一组电池的时间序列数据,它记录了每个储罐在每个时间点的 'state of charge'。我没有进出流量的测量,只有瞬时充电状态。
从这些数据中,我想找出每次充电状态的变化,稍后我将把它与几个小时的消耗量相提并论(在做了一些特定于电池的数学运算之后)。
我写了一个 SQL 查询来实现我的目标:
SELECT time, charge - LAG(charge) OVER (ORDER BY time) AS delta_soc FROM charge_data;
将其放入 Postgres generated column:
ADD COLUMN delta_soc smallint GENERATED ALWAYS AS (charge - LAG(charge) OVER (ORDER BY time)) STORED
如文档中所承诺的那样失败,因为它引用了另一行。
于是,我(成功)做了一个物化视图:
CREATE MATERIALIZED VIEW delta_soc AS
SELECT
time,
batt_uid,
charge,
(charge-LAG(charge) OVER (ORDER BY time)) as delta_charge,
EXTRACT(EPOCH FROM time-LAG(time) OVER (ORDER BY time)) as delta_time
FROM charge_data
ORDER BY time;
但如果能近乎实时地获得这些数据就好了。毕竟,仅提供上一个值的变化是一个“简单”的操作。所以,我查看了 Timescale 的 continuous aggregates。但是,正如文档中所述,您不允许在连续聚合中使用 window 函数,因此连续聚合无效。
然后,就往墙上扔东西,看看有什么东西粘在墙上,我想知道插入时是否可以引用上一行
INSERT INTO charge_data VALUES (..., ([$chargevalue]-LAG(charge) OVER (ORDER BY time)), ...);
HINT: There is a column named "charge" in table "mx_data", but it cannot be referenced from this part of the query.
我知道我可以计算增量
- 插入前
- 插入后通过修改每个 charge_data 行及其增量
- 在 SQL 查询中
- 在查询程序中
但是让数据库计算一次 at/around 插入的值似乎更简单、更整洁,这让我怀疑我遗漏了什么。有什么方法可以在时间尺度上近乎实时地为每一行计算和存储电荷[电池][n]-电荷[电池][n-1]?
我认为插入前触发器可以正常工作。您可以创建一个 before_insert 触发器并在使用之前的参考插入时更新增量 soc。
CREATE TABLE batteries ( time timestamp not null, batt_uid varchar, charge int, delta int);
SELECT create_hypertable('batteries', 'time');
CREATE OR REPLACE FUNCTION update_delta() RETURNS trigger AS
$BODY$
DECLARE
previous_charge integer;
BEGIN
select charge
into previous_charge
from batteries where batt_uid = NEW.batt_uid
order by time desc limit 1;
IF NEW.charge IS NOT NULL THEN
IF previous_charge IS NOT NULL THEN
NEW.delta = NEW.charge - previous_charge;
ELSE
NEW.delta = 0;
END IF;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER update_delta_on_insert
BEFORE INSERT
ON batteries
FOR EACH ROW
EXECUTE PROCEDURE update_delta();
测试
INSERT INTO batteries VALUES
('2021-08-26 10:09:00'::timestamp, 'battery-1', 32),
('2021-08-26 10:09:01'::timestamp, 'battery-1', 34),
('2021-08-26 10:09:02'::timestamp, 'battery-1', 38);
INSERT INTO batteries VALUES
('2021-08-26 10:09:00'::timestamp, 'battery-2', 0),
('2021-08-26 10:09:01'::timestamp, 'battery-2', 4),
('2021-08-26 10:09:02'::timestamp, 'battery-2', 28),
('2021-08-26 10:09:03'::timestamp, 'battery-2', 32),
('2021-08-26 10:09:04'::timestamp, 'battery-2', 28);
输出自:
SELECT * FROM batteries;
┌─────────────────────┬───────────┬────────┬───────┐
│ time │ batt_uid │ charge │ delta │
├─────────────────────┼───────────┼────────┼───────┤
│ 2021-08-26 10:09:00 │ battery-1 │ 32 │ 0 │
│ 2021-08-26 10:09:01 │ battery-1 │ 34 │ 2 │
│ 2021-08-26 10:09:02 │ battery-1 │ 38 │ 4 │
│ 2021-08-26 10:09:00 │ battery-2 │ 0 │ 0 │
│ 2021-08-26 10:09:01 │ battery-2 │ 4 │ 4 │
│ 2021-08-26 10:09:02 │ battery-2 │ 28 │ 24 │
│ 2021-08-26 10:09:03 │ battery-2 │ 32 │ 4 │
│ 2021-08-26 10:09:04 │ battery-2 │ 28 │ -4 │
└─────────────────────┴───────────┴────────┴───────┘
我在 TimescaleDB 中存储了大量关于一组电池的时间序列数据,它记录了每个储罐在每个时间点的 'state of charge'。我没有进出流量的测量,只有瞬时充电状态。
从这些数据中,我想找出每次充电状态的变化,稍后我将把它与几个小时的消耗量相提并论(在做了一些特定于电池的数学运算之后)。
我写了一个 SQL 查询来实现我的目标:
SELECT time, charge - LAG(charge) OVER (ORDER BY time) AS delta_soc FROM charge_data;
将其放入 Postgres generated column:
ADD COLUMN delta_soc smallint GENERATED ALWAYS AS (charge - LAG(charge) OVER (ORDER BY time)) STORED
如文档中所承诺的那样失败,因为它引用了另一行。
于是,我(成功)做了一个物化视图:
CREATE MATERIALIZED VIEW delta_soc AS
SELECT
time,
batt_uid,
charge,
(charge-LAG(charge) OVER (ORDER BY time)) as delta_charge,
EXTRACT(EPOCH FROM time-LAG(time) OVER (ORDER BY time)) as delta_time
FROM charge_data
ORDER BY time;
但如果能近乎实时地获得这些数据就好了。毕竟,仅提供上一个值的变化是一个“简单”的操作。所以,我查看了 Timescale 的 continuous aggregates。但是,正如文档中所述,您不允许在连续聚合中使用 window 函数,因此连续聚合无效。
然后,就往墙上扔东西,看看有什么东西粘在墙上,我想知道插入时是否可以引用上一行
INSERT INTO charge_data VALUES (..., ([$chargevalue]-LAG(charge) OVER (ORDER BY time)), ...);
HINT: There is a column named "charge" in table "mx_data", but it cannot be referenced from this part of the query.
我知道我可以计算增量
- 插入前
- 插入后通过修改每个 charge_data 行及其增量
- 在 SQL 查询中
- 在查询程序中
但是让数据库计算一次 at/around 插入的值似乎更简单、更整洁,这让我怀疑我遗漏了什么。有什么方法可以在时间尺度上近乎实时地为每一行计算和存储电荷[电池][n]-电荷[电池][n-1]?
我认为插入前触发器可以正常工作。您可以创建一个 before_insert 触发器并在使用之前的参考插入时更新增量 soc。
CREATE TABLE batteries ( time timestamp not null, batt_uid varchar, charge int, delta int);
SELECT create_hypertable('batteries', 'time');
CREATE OR REPLACE FUNCTION update_delta() RETURNS trigger AS
$BODY$
DECLARE
previous_charge integer;
BEGIN
select charge
into previous_charge
from batteries where batt_uid = NEW.batt_uid
order by time desc limit 1;
IF NEW.charge IS NOT NULL THEN
IF previous_charge IS NOT NULL THEN
NEW.delta = NEW.charge - previous_charge;
ELSE
NEW.delta = 0;
END IF;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER update_delta_on_insert
BEFORE INSERT
ON batteries
FOR EACH ROW
EXECUTE PROCEDURE update_delta();
测试
INSERT INTO batteries VALUES
('2021-08-26 10:09:00'::timestamp, 'battery-1', 32),
('2021-08-26 10:09:01'::timestamp, 'battery-1', 34),
('2021-08-26 10:09:02'::timestamp, 'battery-1', 38);
INSERT INTO batteries VALUES
('2021-08-26 10:09:00'::timestamp, 'battery-2', 0),
('2021-08-26 10:09:01'::timestamp, 'battery-2', 4),
('2021-08-26 10:09:02'::timestamp, 'battery-2', 28),
('2021-08-26 10:09:03'::timestamp, 'battery-2', 32),
('2021-08-26 10:09:04'::timestamp, 'battery-2', 28);
输出自:
SELECT * FROM batteries;
┌─────────────────────┬───────────┬────────┬───────┐
│ time │ batt_uid │ charge │ delta │
├─────────────────────┼───────────┼────────┼───────┤
│ 2021-08-26 10:09:00 │ battery-1 │ 32 │ 0 │
│ 2021-08-26 10:09:01 │ battery-1 │ 34 │ 2 │
│ 2021-08-26 10:09:02 │ battery-1 │ 38 │ 4 │
│ 2021-08-26 10:09:00 │ battery-2 │ 0 │ 0 │
│ 2021-08-26 10:09:01 │ battery-2 │ 4 │ 4 │
│ 2021-08-26 10:09:02 │ battery-2 │ 28 │ 24 │
│ 2021-08-26 10:09:03 │ battery-2 │ 32 │ 4 │
│ 2021-08-26 10:09:04 │ battery-2 │ 28 │ -4 │
└─────────────────────┴───────────┴────────┴───────┘