如何在 SQLite 触发器中使用或替换 'WITH RECURSIVE' 来更新树结构的 table
How to use or replace 'WITH RECURSIVE' in a SQLite trigger to update a tree-structured table
在 SQLite 中,我有一个名为 layer
的树结构 table,其中包含列 (id, ..., parentId)
。一个正常的 table 称为 dir
,列为 (id, ..., modifiedTime)
。情况是:
一旦 dir
中的一些行更新了新的 modifiedTime,它们的所有父级也应该更新。保证modifiedTime不减
没有触发器,我可以使用这个 sql 来完成它(通过使用 WITH RECURSIVE 子句):
WITH RECURSIVE P(id) AS (
SELECT parentId FROM layer WHERE id="The Id of Modified Row"
UNION ALL
SELECT L.parentId FROM layer AS L, P WHERE L.id=P.id)
UPDATE dir SET modifiedT=CURRENT_TIMESTAMP WHERE id IN P;
但是当我将 sql 放入触发器时,UPDATE 语句出错。看完 SQLite offical doc,我明白了 The WITH clause cannot be used within a CREATE TRIGGER.
就是这个问题
如何让触发器做我想做的事?
换句话说,如何替换触发器中的 'WITH' 子句?
您可以创建一个 recursive trigger(作为 SQLite 3.6.18 提供),按照此行。
CREATE TRIGGER tr_update_parent_modifiedT
AFTER UPDATE OF modifiedT ON layer
BEGIN
UPDATE
layer
SET
modifiedT = (SELECT modifiedT FROM NEW WHERE id = layer.id)
WHERE
id IN (SELECT parentId FROM NEW);
END;
此触发器仅对 modifiedT
的更改作出反应,并在 parent 行上复制其值。相关子查询语法是必需的,因为 NEW
总是可以包含多个记录。
CREATE TRIGGER tr_update_self_modifiedT
AFTER UPDATE OF parentId, name, all, other, columns, except_modifiedT ON layer
BEGIN
UPDATE
layer
SET
modifiedT = CURRENT_TIMESTAMP
WHERE
id IN (SELECT id FROM NEW);
END;
此触发器对任何列的更改做出反应 除了 modifiedT
并设置当前时间戳。它们结合起来应该可以达到预期的效果。
你应该再创建两个触发器覆盖INSERT
和DELETE
并设置parentmodifiedT
,否则adding/removingchildren将不反映 parents.
请注意,必须在连接级别启用递归触发器:
PRAGMA recursive_triggers = ON;
在 SQLite 中,我有一个名为 layer
的树结构 table,其中包含列 (id, ..., parentId)
。一个正常的 table 称为 dir
,列为 (id, ..., modifiedTime)
。情况是:
一旦 dir
中的一些行更新了新的 modifiedTime,它们的所有父级也应该更新。保证modifiedTime不减
没有触发器,我可以使用这个 sql 来完成它(通过使用 WITH RECURSIVE 子句):
WITH RECURSIVE P(id) AS (
SELECT parentId FROM layer WHERE id="The Id of Modified Row"
UNION ALL
SELECT L.parentId FROM layer AS L, P WHERE L.id=P.id)
UPDATE dir SET modifiedT=CURRENT_TIMESTAMP WHERE id IN P;
但是当我将 sql 放入触发器时,UPDATE 语句出错。看完 SQLite offical doc,我明白了 The WITH clause cannot be used within a CREATE TRIGGER.
就是这个问题
如何让触发器做我想做的事?
换句话说,如何替换触发器中的 'WITH' 子句?
您可以创建一个 recursive trigger(作为 SQLite 3.6.18 提供),按照此行。
CREATE TRIGGER tr_update_parent_modifiedT
AFTER UPDATE OF modifiedT ON layer
BEGIN
UPDATE
layer
SET
modifiedT = (SELECT modifiedT FROM NEW WHERE id = layer.id)
WHERE
id IN (SELECT parentId FROM NEW);
END;
此触发器仅对 modifiedT
的更改作出反应,并在 parent 行上复制其值。相关子查询语法是必需的,因为 NEW
总是可以包含多个记录。
CREATE TRIGGER tr_update_self_modifiedT
AFTER UPDATE OF parentId, name, all, other, columns, except_modifiedT ON layer
BEGIN
UPDATE
layer
SET
modifiedT = CURRENT_TIMESTAMP
WHERE
id IN (SELECT id FROM NEW);
END;
此触发器对任何列的更改做出反应 除了 modifiedT
并设置当前时间戳。它们结合起来应该可以达到预期的效果。
你应该再创建两个触发器覆盖INSERT
和DELETE
并设置parentmodifiedT
,否则adding/removingchildren将不反映 parents.
请注意,必须在连接级别启用递归触发器:
PRAGMA recursive_triggers = ON;