如何创建 PostgreSQL TRIGGER 以在 INSERT 后自动计算列?

问题描述 投票:0回答:1

我试图在

INSERT
中的每个新行
PostgreSQL
之后填充一些计算列,但我无法让它工作。

我已经阅读了这些帖子我知道这些是针对

SQLite
的 - 这个问题最初是针对
SQLite
的,但我已将其更改为
PostgreSQL
- 一旦我得到,我会看看
SQLite
PG
版本正在运行
):

  1. sqlite-插入后触发
  2. sqlite-geopackage-插入后触发计算qgis中的长度

  1. PostgreSQL 创建触发器

但我想知道我是否使用

SELECT
语句和
FOR EACH ROW
中的
TRIGGER
语句,因为我想要计算刚刚插入的行的值,而不是所有行。

有关更多历史记录,这个问题是我上一个问题的延续:

这是桌子设置:

CREATE TABLE myTable (
    datetime TEXT,
    sys_id INT,
    cputil REAL,
    memfree REAL,
    sessnum INT,
    util_lag REAL,   -- to be calculated AFTER INSERT via TRIGGER
    mem_lag REAL,    -- to be calculated AFTER INSERT via TRIGGER
    util_diff REAL,  -- to be calculated AFTER INSERT via TRIGGER
    mem_diff REAL    -- to be calculated AFTER INSERT via TRIGGER
    util_change TEXT -- to be calculated AFTER INSERT via TRIGGER
);

现在进行

TRIGGER
设置。 我尝试了以下 SQL
TRIGGER
语法,但无法让它工作:

CREATE TRIGGER tr_fill_calculated_columns
    AFTER INSERT ON myTable
BEGIN
    UPDATE myTable
        SET util_lag = LAG(cputil) OVER (ORDER BY datetime),
        SET mem_lag = LAG(memfree) OVER (ORDER BY datetime),
        SET util_diff = cputil - util_lag,
        SET mem_diff = memfree - mem_lag,
        SET util_change = CASE
            WHEN util_diff > 0 THEN 'Up'
            WHEN util_diff < 0 THEN 'Down'
    WHERE datetime = NEW.datetime AND sys_id = NEW.sys_id
END;

我还尝试了以下方法(我认为这更接近

PostgreSQL
中需要完成的方式):

CREATE OR REPLACE FUNCTION fn_calculate_columns_after_insert
    RETURNS TRIGGER
    LANGUAGE PLPGSQL
    AS $$
BEGIN
    NEW.util_lag := (SELECT LAG(cputil) OVER (ORDER BY datetime) FROM myTable);
    NEW.mem_lag := (SELECT LAG(memfree) OVER (ORDER BY datetime) FROM myTable);
    NEW.util_diff := cputil - util_lag;
    NEW.mem_diff := memfree - mem_lag;
    IF NEW.util_diff > 0 THEN
        NEW.util_change := 'Up';
    IF NEW.util_diff < 0 THEN
        NEW.util_change := 'Down';
    ELSE
        NEW.util_change := '';
    RETURN NEW;
END;
$$

CREATE TRIGGER tr_fill_calculated_columns
    AFTER INSERT ON myTable
    FOR EACH ROW
    EXECUTE FUNCTION fn_calculate_columns_after_insert();

无论我尝试什么,我都会不断获得

SQL error [42601]: ERROR: syntax error at or near ";"
或接近其他角色。这真让我抓狂。官方文档或示例教程都没有给出我想要做什么的示例,我认为这并不难 - 根据新插入的行中的现有列值更新简单的计算列。在我看来非常基本。

完整的数据集包含数亿行,因此性能很重要 - 我只希望 TRIGGER 在 INSERT 之后立即计算最后一行,此后不再查询它,也就是说,我只希望 TRIGGER 作用于新的正在插入的行(每次插入新行时)。

为了帮助明确我在结果中寻找什么,这里有一些触发前数据示例:

datetime,sys_id,cputil,memfree,sessnum
2019/05/03 08:06:14,100,0.57,0.51,47
2019/05/03 08:11:14,100,0.47,0.62,43
2019/05/03 08:16:14,100,0.56,0.57,62
2019/05/03 08:21:14,100,0.57,0.56,50
2019/05/03 08:26:14,100,0.35,0.46,43
2019/05/03 08:31:14,100,0.41,0.58,48
2019/05/03 08:36:14,100,0.57,0.35,58
2019/05/03 08:41:14,100,0.41,0.4,58
2019/05/03 08:46:14,100,0.53,0.35,62
2019/05/03 08:51:14,100,0.51,0.6,45
2019/05/03 08:56:14,100,0.32,0.37,47
2019/05/03 09:01:14,100,0.62,0.59,60
2019/05/03 09:06:14,100,0.66,0.72,57
2019/05/03 09:11:14,100,0.54,0.54,44
2019/05/03 09:16:14,100,0.29,0.4,47
2019/05/03 09:21:14,100,0.43,0.68,66
2019/05/03 09:26:14,100,0.49,0.66,65
2019/05/03 09:31:14,100,0.64,0.55,66
2019/05/03 09:36:14,100,0.42,0.6,42
2019/05/03 09:41:14,100,0.55,0.59,63

这是所需的触发后结果的示例,其中计算列由触发器/功能填充:

datetime,sys_id,cputil,memfree,sessnum,util_lag,mem_lag,util_diff,mem_diff,util_change
2019/05/03 08:06:14,100,0.57,0.51,47,[NULL],[NULL],[NULL],[NULL],[NULL]
2019/05/03 08:11:14,100,0.47,0.62,43,0.57,0.51,-0.1,0.11,Down
2019/05/03 08:16:14,100,0.56,0.57,62,0.47,0.62,0.0900000000000001,-0.05,Up
2019/05/03 08:21:14,100,0.57,0.56,50,0.56,0.57,0.0099999999999999,-0.0099999999999999,Up
2019/05/03 08:26:14,100,0.35,0.46,43,0.57,0.56,-0.22,-0.1,Down
2019/05/03 08:31:14,100,0.41,0.58,48,0.35,0.46,0.06,0.12,Up
2019/05/03 08:36:14,100,0.57,0.35,58,0.41,0.58,0.16,-0.23,Up
2019/05/03 08:41:14,100,0.41,0.4,58,0.57,0.35,-0.16,0.05,Down
2019/05/03 08:46:14,100,0.53,0.35,62,0.41,0.4,0.12,-0.05,Up
2019/05/03 08:51:14,100,0.51,0.6,45,0.53,0.35,-0.02,0.25,Down
2019/05/03 08:56:14,100,0.32,0.37,47,0.51,0.6,-0.19,-0.23,Down
2019/05/03 09:01:14,100,0.62,0.59,60,0.32,0.37,0.3,0.22,Up
2019/05/03 09:06:14,100,0.66,0.72,57,0.62,0.59,0.04,0.13,Up
2019/05/03 09:11:14,100,0.54,0.54,44,0.66,0.72,-0.12,-0.18,Down
2019/05/03 09:16:14,100,0.29,0.4,47,0.54,0.54,-0.25,-0.14,Down
2019/05/03 09:21:14,100,0.43,0.68,66,0.29,0.4,0.14,0.28,Up
2019/05/03 09:26:14,100,0.49,0.66,65,0.43,0.68,0.06,-0.02,Up
2019/05/03 09:31:14,100,0.64,0.55,66,0.49,0.66,0.15,-0.11,Up
2019/05/03 09:36:14,100,0.42,0.6,42,0.64,0.55,-0.22,0.0499999999999999,Down
2019/05/03 09:41:14,100,0.55,0.59,63,0.42,0.6,0.13,-0.01,Up

最后,我也想知道如何在 SQLite 中执行此操作,即执行完全相同的操作的正确 SQLite 语法是什么?

postgresql sqlite triggers sql-insert sql-function
1个回答
0
投票

从您的

SQL error [42601]: ERROR: syntax error at or near ";"
开始:演示

  1. 在 PL/pgSQL 中,
    IF
    条件语句
    需要后续的
    END IF
    。该错误具有误导性,因为解析器正在寻找该错误,找到了最近的
    END
    ,即最后的那个。它想要一个
    END IF
    ,却得到了一个
    END;
    - 因此投诉。
  2. 您的签名中缺少括号。
  3. 函数体中的最后一个分号是可选的。
CREATE OR REPLACE FUNCTION fn_calculate_columns_after_insert()--missing parentheses here
    RETURNS TRIGGER LANGUAGE PLPGSQL AS $f$
BEGIN
    NEW.util_lag := (SELECT LAG(cputil) OVER (ORDER BY datetime) FROM myTable);
    NEW.mem_lag := (SELECT LAG(memfree) OVER (ORDER BY datetime) FROM myTable);
    NEW.util_diff := cputil - util_lag;
    NEW.mem_diff := memfree - mem_lag;
    IF NEW.util_diff > 0 THEN
        NEW.util_change := 'Up';
    END IF;--this was missing
    IF NEW.util_diff < 0 THEN
        NEW.util_change := 'Down';
    ELSE
        NEW.util_change := '';
    END IF;--this was missing
    RETURN NEW;
END;--This semicolon is optional because it's immediately followed by closing dollar qoutes.
$f$;--This semicolon was missing. It is not optional, because it ends the whole `create function` statement

现在它已被接受,没有错误,但我必须看看它是否符合您的要求。

© www.soinside.com 2019 - 2024. All rights reserved.