如何创建 SQLite 触发器以在 INSERT 后自动计算列?

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

这个问题是我之前的问题的延续,我对此有一个可行的答案:

但现在我需要在 SQLite 中做同样的事情。我读过这个问题:

但它缺乏足够的细节供我使用它,因此这个更详细的问题。

鉴于此表:

CREATE TABLE myTable 
(
    datetime TEXT,
    gen_year INT GENERATED ALWAYS AS (SUBSTRING(datetime,7,4)) STORED,
    gen_mon INT GENERATED ALWAYS AS (SUBSTRING(datetime,4,2)) STORED,
    gen_date INT GENERATED ALWAYS AS (SUBSTRING(datetime,1,2)) STORED,
    gen_hr INT GENERATED ALWAYS AS (SUBSTRING(datetime,12,2)) STORED,
    gen_min INT GENERATED ALWAYS AS (SUBSTRING(datetime,15,2)) STORED,
    gen_sec INT GENERATED ALWAYS AS (SUBSTRING(datetime,18,2)) STORED,
    gen_ms INT GENERATED ALWAYS AS (SUBSTRING(datetime,21,3)) STORED,
    gen_isodate TEXT GENERATED ALWAYS AS (
        FORMAT("%04d",gen_year) || "-" ||
        FORMAT("%02d",gen_mon) || "-" ||
        FORMAT("%02d",gen_date) || " " ||
        FORMAT("%02d",gen_hr) || ":" ||
        FORMAT("%02d",gen_min) || ":" ||
        FORMAT("%02d",gen_sec) || "." ||
        FORMAT("%03d",gen_ms)
    ) STORED,
    sys_id INT,
    cputil REAL,
    memfree REAL,
    sessnum INT,
    util_lag REAL,   -- meant to be filled by TRIGGER upon/after INSERT
    mem_lag REAL,    -- meant to be filled by TRIGGER upon/after INSERT
    util_diff REAL,  -- meant to be filled by TRIGGER upon/after INSERT
    mem_diff REAL,   -- meant to be filled by TRIGGER upon/after INSERT
    util_change TEXT -- meant to be filled by TRIGGER upon/after INSERT
);

我正在尝试使用触发器来计算 ROW 之间的

cputil
memfree
列中的差异,并将文本字符串添加到
util_change
列,所有新行都在
INSERT
上。

我有以下被接受的触发器(即它不会抛出任何错误) - 在 ChatGPT 的帮助下创建:

-- chatGPT v1 with updates
CREATE TRIGGER tr_fill_calculated_columns
    AFTER INSERT ON myTable
BEGIN
    UPDATE myTable
    SET util_lag = (SELECT LAG(cputil) OVER (ORDER BY gen_isodate ASC) FROM myTable WHERE datetime = NEW.datetime),
        mem_lag = (SELECT LAG(memfree) OVER (ORDER BY gen_isodate ASC) FROM myTable WHERE datetime = NEW.datetime),
        util_diff = NEW.cputil - NEW.util_lag,
        mem_diff = NEW.freemem - NEW.mem_lag
    WHERE datetime = NEW.datetime;
END;

但问题是它根本不起作用 - 触发器无法计算我需要它的列。当我使用以下数据执行

INSERT
时:

INSERT INTO myTable (datetime,sys_id,cputil,memfree,sessnum) 
VALUES
 ("06.03.2021 23:10:49.057",100,0.5,0.9,97)
,("24.03.2021 17:04:20.715",100,0.28,0.19,167)
,("09.06.2021 10:24:09.880",100,0.59,0.25,138)
,("30.06.2021 12:41:38.694",100,0.34,0.49,102)
,("28.07.2021 23:12:40.555",100,0.84,0.03,95)
,("22.10.2021 03:55:31.215",100,0.44,0.04,56)
,("25.08.2022 11:11:01.672",100,0.7,0.58,120)
,("25.08.2022 11:11:02.119",100,0.97,0.18,155)
,("25.08.2022 11:11:03.893",100,0.68,0.16,123)
,("25.08.2022 11:11:04.390",100,0.25,0.67,167)
,("25.08.2022 11:11:05.538",100,0.48,0.4,169)
,("25.08.2022 11:11:06.204",100,0.96,0.47,180)
,("25.08.2022 11:11:07.070",100,0.94,0.07,95)
,("25.08.2022 11:11:08.845",100,0.5,0.48,132)
,("25.08.2022 11:11:09.919",100,0.02,0.07,154)
,("25.08.2022 11:11:10.280",100,0.41,0.05,64)
,("25.08.2022 11:11:11.100",100,0.68,0.77,88)
,("25.08.2022 11:11:12.687",100,0.81,0.05,57)
,("25.08.2022 11:11:13.707",100,0.25,0.71,159)
,("25.08.2022 11:11:14.922",100,0.23,0.58,193)
,("25.08.2022 11:11:15.836",100,0.87,0.32,158)
,("25.08.2022 11:11:16.695",100,0.53,0.46,177)
,("25.08.2022 11:11:17.576",100,0.77,0.46,188)
,("25.08.2022 11:11:18.932",100,0.45,0.47,56)
,("25.08.2022 11:11:19.638",100,0.87,0.41,184)
,("25.08.2022 11:11:20.489",100,0.55,0.05,54)
,("25.08.2022 11:11:21.404",100,0.31,0.02,72)
,("25.08.2022 11:11:22.704",100,0.78,0.52,152)
,("25.08.2022 11:11:23.166",100,0.12,0.34,119)
,("25.08.2022 11:11:24.067",100,0.98,0.68,102)
,("25.08.2022 11:11:25.423",100,0.85,0.81,136)
,("25.08.2022 11:11:26.544",100,0.91,0,169)
,("25.08.2022 11:11:27.835",100,0.82,0.95,186)
,("25.08.2022 11:11:28.055",100,0.53,0.35,50)
,("25.08.2022 11:11:29.769",100,0.39,0.79,144)
,("25.08.2022 11:11:30.935",100,0.39,0.15,180)
,("25.08.2022 11:11:31.153",100,0.76,0.26,116)
,("25.08.2022 11:11:32.305",100,0.76,0.06,175)
,("25.08.2022 11:11:33.392",100,0.91,0.98,173)
,("25.08.2022 11:11:34.458",100,0.39,0.18,111)
,("25.08.2022 11:11:35.227",100,0.73,0.31,75)
,("25.08.2022 11:11:36.584",100,0.8,0.58,56)
,("25.08.2022 11:11:37.619",100,0.11,0.84,51)
,("25.08.2022 11:11:38.407",100,0.67,0.85,166)
,("25.08.2022 11:11:39.070",100,0.28,0.31,159)
,("25.08.2022 11:11:40.674",100,0.05,0.38,176)
,("25.08.2022 11:11:41.422",100,0.87,0.47,110)
,("25.08.2022 11:11:42.235",100,0.64,0.97,194)
,("25.08.2022 11:11:43.780",100,0.07,0.36,63)
,("25.08.2022 11:11:44.903",100,0.5,0.17,89)
RETURNING *;

SELECT * FROM myTable;

util_lag
mem_lag
util_diff
mem_diff
都是所有行的
[NULL]
,而不仅仅是第一行(预期)。

输出示例:

我还尝试将最后四行计算行添加到

util_change
列的触发器中,如下所示:

DROP TRIGGER tr_fill_calculated_columns;

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

但是失败并出现错误:

SQL 错误 [2]:[SQLITE_ERROR] SQL 错误或丢失数据库(“util_change”附近:语法错误)

我尝试让 ChatGPT 帮助我添加最终的计算列

util_change
,它产生了以下结果:

-- Create a trigger that fires after inserting a new row into my_table
CREATE TRIGGER tr_fill_calculated_columns
AFTER INSERT ON myTable
BEGIN
    -- Declare variables to store the previous row's values
    DECLARE prev_cputil REAL;
    DECLARE prev_freemem REAL;
    DECLARE util_diff REAL;
    DECLARE mem_diff REAL;
    DECLARE util_change TEXT;

    -- Get the previous row's values for cputil and freemem
    SELECT cputil, freemem
    INTO prev_cputil, prev_freemem
    FROM myTable
    WHERE datetime = (SELECT MAX(datetime) FROM myTable);

    -- Calculate the differences
    SET util_diff = NEW.cputil - prev_cputil;
    SET mem_diff = NEW.freemem - prev_freemem;

    -- Determine the value for util_change
    IF util_diff > 0 THEN
        SET util_change = 'Up';
    ELSEIF util_diff < 0 THEN
        SET util_change = 'Down';
    ELSE
        SET util_change = '';
    END IF;

    -- Update the inserted row with calculated values
    UPDATE myTable
    SET util_lag = prev_cputil,
        mem_lag = prev_freemem,
        util_diff = util_diff,
        mem_diff = mem_diff,
        util_change = util_change
    WHERE datetime = NEW.datetime;
END;

但这也因语法错误而失败:

SQL 错误 [2]:[SQLITE_ERROR] SQL 错误或丢失数据库(“DECLARE”附近:语法错误)

有人可以在需要的地方对我的 SQLite 触发器代码进行更正吗?

sql sqlite triggers sql-insert calculated-columns
2个回答
0
投票

您可以通过

instead of
触发器重定向和修改视图上的插入:演示

引导行将简化触发器:

insert into myTable(datetime)
select '-infinity';

没有它,触发器必须始终考虑两种情况:

  • 如果没有行,则插入传入行而不修改它
  • 如果有任何行,计算相对
    _lag
    _diff

通过提前添加初始行,您无需考虑第一种情况。

CREATE INDEX dtidx ON myTable (datetime);
CREATE VIEW v_myTable AS SELECT * FROM myTable ORDER BY datetime DESC LIMIT 1;
CREATE TRIGGER cust_addr_chng
INSTEAD OF INSERT ON v_myTable 
BEGIN
  INSERT INTO myTable
  SELECT NEW.datetime,
         NEW.sys_id,
         NEW.cputil,
         NEW.memfree,
         NEW.sessnum,
         previous.cputil,--util_lag
         previous.memfree,--mem_lag
         NEW.cputil-previous.cputil,--util_diff 
         NEW.memfree-previous.memfree,--mem_diff
         CASE WHEN NEW.cputil-previous.cputil > 0
              THEN 'Up'
              WHEN NEW.cputil-previous.cputil < 0
              THEN 'Down'
              WHEN NEW.cputil-previous.cputil = 0
              THEN ''
         END --util_change
  FROM myTable AS previous
  ORDER BY datetime DESC
  LIMIT 1;
END;
日期时间 sys_id cpuutil 无内存 sessnum util_lag mem_lag util_diff mem_diff util_change
-无穷大
2019/05/03 08:06:14 100 0.57 0.51 47
2019/05/03 08:11:14 100 0.47 0.62 43 0.57 0.51 -0.09999999999999998 0.10999999999999999 向下
2019/05/03 08:16:14 100 0.56 0.57 62 0.47 0.62 0.09000000000000008 -0.050000000000000044 向上
2019/05/03 08:21:14 100 0.57 0.56 50 0.56 0.57 0.009999999999999898 -0.009999999999999898 向上
2019/05/03 08:26:14 100 0.35 0.46 43 0.57 0.56 -0.21999999999999997 -0.10000000000000003 向下
2019/05/03 08:31:14 100 0.41 0.58 48 0.35 0.46 0.06 0.11999999999999994 向上

0
投票

作为在

instead of
操作中动态修改插入的触发器的替代方案,您可以修改行
after
事实:demo

CREATE INDEX dtidx ON myTable (datetime);
CREATE TRIGGER cust_addr_chng
AFTER INSERT ON myTable 
BEGIN
  UPDATE myTable
  SET util_lag    =previous.cputil,
      mem_lag     =previous.memfree,
      util_diff   =NEW.cputil-previous.cputil,
      mem_diff    =NEW.memfree-previous.memfree,
      util_change =CASE WHEN NEW.cputil-previous.cputil > 0
                        THEN 'Up'
                        WHEN NEW.cputil-previous.cputil < 0
                        THEN 'Down'
                        WHEN NEW.cputil-previous.cputil = 0
                        THEN ''
                   END
  FROM (SELECT * FROM myTable
        ORDER BY datetime DESC
        LIMIT 1, 1) AS previous
  WHERE myTable.datetime=NEW.datetime;
END;
"� 755e ��0.56500.560.570.009999999999999898-0.009999999999999898向上2019/05/03 08:26:141000.350.46430.570.56-0.21999999999999997-0.10000000000000003向下2019/05/03 08:31:141000.410.58480.350.460.060.11999999999999994向上
日期时间 sys_id cpuutil 无内存 sessnum util_lag mem_lag util_diff mem_diff util_change
2019/05/03 08:06:14 100 0.57 0.51 47
2019/05/03 08:11:14 100 0.47 0.62 43 0.57 0.51 -0.09999999999999998 0.10999999999999999 向下
2019/05/03 08:16:14 100 0.56 0.57 62 0.47 0.62 0.09000000000000008 -0.050000000000000044 向上
2019/05/03 08:21:14 100 0.57\n"
© www.soinside.com 2019 - 2024. All rights reserved.