【问题标题】:Calculating the change of a value versus the last reading in TimescaleDB计算一个值与 TimescaleDB 中上次读数的变化
【发布时间】:2021-10-26 11:06:07
【问题描述】:

我有大量关于存储在 TimescaleDB 中的一组电池的时间序列数据,这些数据记录了每个油箱每次的“充电状态”。我没有对流入和流出的测量,只有瞬时充电状态。

从这些数据中,我想找出每次充电状态的变化,稍后我将在几个小时内将其存储到消耗中(在进行一些特定于电池的数学运算之后)。

我编写了一个 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。但是,正如在文档中一样,您不允许在连续聚合中使用窗口函数,因此连续聚合无效。

然后,只是往墙上扔东西,看看有什么粘在上面,我想知道我是否可以在插入过程中引用上一行

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 查询中
  • 在查询程序中

但是让数据库在插入时/插入前后计算一次值似乎更简单、更整洁,这让我怀疑我遗漏了一些东西。有没有办法在时间尺度上近实时地为每一行计算和存储charge[battery][n]-charge[battery][n-1]?

【问题讨论】:

标签: postgresql timescaledb


【解决方案1】:

我认为插入前触发器可以正常工作。您可以在插入时使用之前的引用创建 before_insert 触发器并更新 delta 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 │
└─────────────────────┴───────────┴────────┴───────┘

【讨论】:

  • 一直在谷歌搜索,在插入触发器之前我什至从未遇到过!解决方案完美,谢谢
猜你喜欢
  • 2023-03-20
  • 1970-01-01
  • 2019-08-24
  • 2019-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多