数据库和Web应用程序中的层次结构树

时间:2017-06-25 14:23:31

标签: postgresql tree

我想创建将使用树数据结构的Web应用程序。用户将能够创建,更新和删除树。我在PostgreSQL中有下表,称为数据库中的节点:

id INTEGER PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
parent_id INTEGER NULL REFERENCE nodes(id)

获取数据

我希望以下列形式获取数据:

id | name | children
---|------|--------------
 1 |    a | [2,3]
 2 |    b | []
 3 |    c | [4]
 4 |    d | []

我创建了以表单

返回数据的查询
id | name | parent_id
---|------|--------------
 1 |    a | 
 2 |    b | 1
 3 |    c | 1
 4 |    d | 3

这是代码:

WITH RECURSIVE nodes_cte(id, name, parent_id, level) AS (
    SELECT nodes.id, nodes.name, nodes.parent_id, 0 AS level
    FROM nodes 
    WHERE name = 'a'
  UNION ALL
    SELECT nodes.id, nodes.name, nodes.parent_id, level+1
    FROM nodes 
    JOIN nodes_cte
    ON nodes_cte.id = nodes.parent_id
)
SELECT * FROM nodes_cte;

我可以更改SQL代码以获取我想要的内容吗?我应该在app中执行此操作吗?

插入数据

我想知道将数据插入表格的方法是什么。我认为以下方法对我有用:

  1. 在数据库中创建序列
  2. 增加树中元素数量的顺序
  3. 在app中手动计算ID并在表格中插入元素
  4. 有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

CREATE TABLE nodes
        ( id INTEGER PRIMARY KEY
        , name VARCHAR(50) NOT NULL UNIQUE
        , parent_id INTEGER NULL REFERENCES nodes(id)
        );


-- I created query which returns data in form
INSERT INTO nodes(id,name,parent_id)VALUES
 ( 1 , 'a' , NULL)
 ,( 2 , 'b' , 1)
 ,( 3 , 'c' , 1)
 ,( 4 , 'd' , 3)
        ;

SELECT p.id, p.name
        , array_agg(c.id) AS children
FROM nodes p
LEFT JOIN nodes c ON c.parent_id = p.id
GROUP BY p.id, p.name
        ;

结果:

 id | name | children 
----+------+----------
  1 | a    | {2,3}
  2 | b    | {NULL}
  3 | c    | {4}
  4 | d    | {NULL}
(4 rows)

额外:使用generate_series()插入一堆记录。每个记录都有id / 3作为父记录(除非为零)。

INSERT INTO  nodes(id,name,parent_id)
SELECT gs, 'zzz_'|| gs::text, NULLIF(gs/3 , 0)
FROM generate_series ( 5,25) gs
        ;

插入/更新数据

通常情况下,您的前端不应该混乱序列,而是将其留给DBMS。您已在UNIQUE上设置name约束,因为它是自然键。因此,您的前端应使用该键来寻址节点表中的行,如:

CREATE TABLE nodes2
        ( id SERIAL NOT NULL PRIMARY KEY
        , name VARCHAR(50) NOT NULL UNIQUE
        , parent_id INTEGER NULL REFERENCES nodes(id)
        );

INSERT INTO  nodes2(name,parent_id)
SELECT 'Omg_'|| gs::text, NULLIF(gs/3 , 0)
FROM generate_series ( 1,15) gs
        ;

PREPARE upd (text, text) AS
        -- child, parent
UPDATE nodes2 c
SET parent_id = p.id
FROM nodes2 p
WHERE p.name = $2 -- parent
AND c.name = $1   -- child
        ;

EXECUTE upd( 'Omg_12', 'Omg_11');
EXECUTE upd( 'Omg_15', 'Omg_11');

结果:

CREATE TABLE
INSERT 0 15
PREPARE
UPDATE 1
UPDATE 1
 id |  name  | children  
----+--------+-----------
  1 | Omg_1  | {3,4,5}
  2 | Omg_2  | {6,7,8}
  3 | Omg_3  | {9,10,11}
  4 | Omg_4  | {13,14}
  5 | Omg_5  | {NULL}
  6 | Omg_6  | {NULL}
  7 | Omg_7  | {NULL}
  8 | Omg_8  | {NULL}
  9 | Omg_9  | {NULL}
 10 | Omg_10 | {NULL}
 11 | Omg_11 | {15,12}
 12 | Omg_12 | {NULL}
 13 | Omg_13 | {NULL}
 14 | Omg_14 | {NULL}
 15 | Omg_15 | {NULL}
(15 rows)