SQLite / Geopackage AFTER INSERT 触发器来计算 QGIS 中的长度

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

我一直遵循此处的指南:https://www.northrivergeographic.com/adding-triggers-to-geopackage/将触发器添加到 Geopackage 文件中的 SQLite 数据库。几何类型是线(LineStringZM)。

我想要它做的是在创建新记录时使用QGIS数字化工具栏中的

Toggle Editing > Add Line Feature
自动计算线长度并更新名为“长度”的字段。很简单...除了触发器似乎会更新所有记录并添加最新行的长度。

我的代码如下:

CREATE TRIGGER update_Length_after_Insert AFTER INSERT
ON WaterwayOptions
BEGIN
UPDATE WaterwayOptions SET Length = (SELECT ST_Length(new.geom) FROM WaterwayOptions );
END

我考虑添加一个

WHEN old.geom <> new.geom
过滤器(如此处的示例:https://www.sqlitetutorial.net/sqlite-trigger/)子句,但这在创建新记录时会失败。

我的逻辑有什么错误?

sqlite qgis geopackage
1个回答
0
投票

我的逻辑有什么错误?

插入时不旧。?只有新的。?用柱无旧。预选赛。也可能在 WHERE 子句中而不是在 WHEN 中,例如

UPDATE WaterwayOptions SET Length = (SELECT ST_Length(new.geom) FROM WaterwayOptions ) WHERE geom = new.geom;

如果您尝试使用 WHEN 子句来尝试查看新的

geom
之前是否不存在,那么您将会遇到问题,因为在插入之后,就事务而言,它确实存在(BEFORE 被警告)。

如果使用更复杂的 WHEN 子句(请参阅演示)发现已插入新的 geom 行(请参阅演示),则 UPDATE 仍会更新所有行。

因此,需要 UPDATE 上的 WHERE 子句,因此 UPDATE 上的 WHERE 子句很可能是最佳解决方案。

也许可以考虑下面的演示,它近似于您正在做的事情。

它经历 4 个触发器

  1. 原版
  2. 第二次使用建议的 WHERE 子句,
  3. 第三个使用了太简单的 WHEN 子句,最后
  4. 第四个使用更复杂的 WHEN 子句

除了创建触发器之外,代码是相同的(插入相同的数据)

演示代码/SQL:-

/* ATTEMPT 1 (original)*/
DROP TABLE IF EXISTS WaterwayOptions;
CREATE TABLE IF NOT EXISTS WaterwayOptions (woId TEXT PRIMARY KEY, geom TEXT UNIQUE, `length` INTEGER, othercol TEXT DEFAULT 'blah');

CREATE TRIGGER update_Length_after_Insert AFTER INSERT
ON WaterwayOptions
BEGIN
UPDATE WaterwayOptions SET Length = (SELECT Length(new.geom) FROM WaterwayOptions );
END
;

INSERT INTO WaterwayOptions (woid,geom,`length`)
    VALUES
    ('wo1','geoma',10),
    ('wo2','geomaa',10),
    ('wo3','geomaaa',10)
;
SELECT * FROM waterwayoptions;

/* ATTEMPT 2 (WHERE clause for the UPDATE)*/
DROP TABLE IF EXISTS WaterwayOptions;
CREATE TABLE IF NOT EXISTS WaterwayOptions (woId TEXT PRIMARY KEY, geom TEXT UNIQUE, `length` INTEGER, othercol TEXT DEFAULT 'blah');
DROP TRIGGER IF EXISTS update_Length_after_Insert;
CREATE TRIGGER update_Length_after_Insert AFTER INSERT
ON WaterwayOptions
BEGIN
UPDATE WaterwayOptions SET Length = (SELECT Length(new.geom) FROM WaterwayOptions ) WHERE geom=new.geom;
END
;
INSERT INTO WaterwayOptions (woid,geom,`length`)
    VALUES
    ('wo1','geoma',10),
    ('wo2','geomaa',10),
    ('wo3','geomaaa',10)
;
SELECT * FROM waterwayoptions;

/* ATTEMPT 3 (simple WHEN) */
DROP TABLE IF EXISTS WaterwayOptions;
CREATE TABLE IF NOT EXISTS WaterwayOptions (woId TEXT PRIMARY KEY, geom TEXT UNIQUE, `length` INTEGER, othercol TEXT DEFAULT 'blah');
DROP TRIGGER IF EXISTS update_Length_after_Insert;
CREATE TRIGGER update_Length_after_Insert AFTER INSERT
ON WaterwayOptions WHEN new.geom NOT IN (SELECT geom FROM WaterwayOptions)
BEGIN
UPDATE WaterwayOptions SET Length = (SELECT Length(new.geom) FROM WaterwayOptions );
END
;
INSERT INTO WaterwayOptions (woid,geom,`length`)
    VALUES
    ('wo1','geoma',10),
    ('wo2','geomaa',10),
    ('wo3','geomaaa',10)
;
SELECT * FROM waterwayoptions;


/* ATTEMPT 4 (more complex WHEN) */
DROP TABLE IF EXISTS WaterwayOptions;
CREATE TABLE IF NOT EXISTS WaterwayOptions (woId TEXT PRIMARY KEY, geom TEXT UNIQUE, `length` INTEGER, othercol TEXT DEFAULT 'blah');
DROP TRIGGER IF EXISTS update_Length_after_Insert;
CREATE TRIGGER update_Length_after_Insert AFTER INSERT
ON WaterwayOptions WHEN new.geom NOT IN (SELECT geom FROM WaterwayOptions WHERE geom <> new.geom)
BEGIN
UPDATE WaterwayOptions SET Length = (SELECT Length(new.geom) FROM WaterwayOptions);
END
;
INSERT INTO WaterwayOptions (woid,geom,`length`)
    VALUES
    ('wo1','geoma',10),
    ('wo2','geomaa',10),
    ('wo3','geomaaa',10)
;
SELECT * FROM waterwayoptions;

结果(在插入之后选择,因此触发):-

  • 第一次尝试更新所有行(不正确)

  • UPDATE .... WHERE ....
    每行已更新为将 10 更改为 geom 列的长度(正确)

  • 没有更新??? (新的几何行存在,所以在表中!!!)

  • 结果是新的几何行已被排除在 WHEN 子句中考虑之外 BUT 如果没有 UPDATE 的 WHERE 子句,所有行都会更新(因此上面的 2 可能是最佳解决方案)。
© www.soinside.com 2019 - 2024. All rights reserved.