1

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

|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。

先感谢您。

4

1 回答 1

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;

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

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

最好的祝福

于 2012-06-28T14:52:21.073 回答