【问题标题】:Trigger on Update to update all the child nodes触发 Update 以更新所有子节点
【发布时间】:2012-06-12 16:44:40
【问题描述】:

在阅读了几篇关于分层数据表的文章后,我进入了一个如下所示的表: 本地:

|id|name        |parent_id|abbreviature | path        |
------------------------------------------------------- 
|1 |"Shoping"   |NULL     | "Sh"        | "Sh"        |
|2 |"Building A"|1        | "A"         | "Sh.A"      |
|3 |"Building B"|1        | "B"         | "Sh.B"      |
|4 |"Building C"|1        | "C"         | "Sh.C"      |
|5 |"Floor -1"  |2        | "-1"        | "Sh.A.-1"   |
|6 |"Floor 0"   |2        | "0"         | "Sh.A.0"    |
|7 |"Floor 1"   |2        | "1"         | "Sh.A.1"    |
|8 |"Floor 2"   |2        | "2"         | "Sh.A.2"    |
|9 |"Room 101"  |7        | "101"       | "Sh.A.1.101"|
|10|"Hospital"  |NULL     | "Hosp"      | "Hosp"      | 
|11|"Secretary" |10       | "Secrt"     | "Secrt"     |

等等。这种方式特别容易选择一个节点的所有后代。

我创建了这个函数来生成路径:

CREATE OR REPLACE FUNCTION teste1_trig () RETURNS TRIGGER AS '
  DECLARE
        dot    varchar := ''.'';
        npath local.path%TYPE;
  BEGIN
    IF NEW.parent_id IS NULL THEN
        NEW.path:=NEW.abbreviature;
        RETURN NEW;
    ELSEIF NEW.parent_id IS NOT NULL THEN
        SELECT path INTO npath FROM local WHERE id=NEW.parent_id;
        NEW.path:=npath||dot||NEW.abbreviature;
        RETURN NEW;
    END IF;
  END;' LANGUAGE 'plpgsql';

这个功能是由以下触发器激活的:

CREATE TRIGGER trigger_teste
  BEFORE INSERT OR UPDATE
  ON local
  FOR EACH ROW
  EXECUTE PROCEDURE teste1_trig();

一切都完美无缺,除非我从具有子节点的节点更新缩写,子节点仍保留旧路径。

我想更改函数以更新当前行中的所有子项。 这是选择所有孩子的查询:

SELECT id,name,parent_id FROM local WHERE id IN ( 
(WITH RECURSIVE parent AS
(
    SELECT id, parent_id  from local WHERE id = id_from_the_modified_node
    UNION ALL 
    SELECT t.id, t.parent_id FROM parent
    INNER JOIN local t ON parent.id =  t.parent_id
)

SELECT id FROM  parent
WHERE id <> id_from_the_modified_node) );

如果缩写已更新(即更改缩写名称或更改 parent_id),我如何更改要在一系列行中执行的功能?

我正在使用 Postgresql v9.1。

提前谢谢你。

【问题讨论】:

    标签: sql function postgresql triggers plpgsql


    【解决方案1】:

    我找到了我认为最适合这种情况的答案。如果我错了,请纠正我!

    DECLARE 
    id_upd INT[];
    ...
    BEGIN
    ...
    
    SELECT array ( SELECT id FROM local WHERE parent_id=NEW.id ) into id_upd; --- select direct childs
        IF id_upd IS NOT NULL THEN              
            FOREACH i IN ARRAY id_upd LOOP      
               UPDATE local SET path=NEW.path||'.'||abbreviature where id=i; --- update them
            END loop;       
        END IF;
    
    END;
    

    这样我只需更新节点的所有直接子节点,然后触发器再次触发子节点的子节点,依此类推。

    不要忘记检查父节点是否不是该节点的后代,这样您将创建一个无限循环。

    最好的问候

    【讨论】:

      猜你喜欢
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多