如何在 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 并设置当前时间戳。它们结合起来应该可以达到预期的效果。

你应该再创建两个触发器覆盖INSERTDELETE并设置parentmodifiedT,否则adding/removingchildren将不反映 parents.

请注意,必须在连接级别启用递归触发器:

PRAGMA recursive_triggers = ON;