Эффективное копирование дерева, смоделированного списком смежности в postgres - PullRequest
0 голосов
/ 31 января 2020

У меня есть следующая таблица:

CREATE TABLE tree_node (
    id serial primary key,
    name character varying(255),
    parent_id integer references tree (id)
);

Таблица содержит много деревьев с количеством узлов до 1000.

(я могу запросить дерево и его потомки эффективно с помощью рекурсивного запроса).

Однако мне нужно иметь возможность скопировать отдельное дерево за одну операцию . Скажем, у меня есть дерево с 3 узлами, идентификаторы 1,2,3 (это потенциально большое дерево). Я хотел бы сделать его копию, т.е. создать новые узлы с новыми идентификаторами. (Здесь скопированное дерево с идентификаторами 4,5,6):

id |      name       | parent_id
----+-----------------+-----------
  1 | NodeA           |
  2 | NodeA.1         |         1
  3 | NodeA.1.1       |         2
  4 | NodeA(copy)     |
  5 | NodeA.1(copy)   |         4
  6 | NodeA.1.1(copy) |         5

Есть ли способ скопировать дерево и его потомков более эффективно, чем вставка каждого узла дерева отдельно (поскольку необходим новый parent_id)

1 Ответ

0 голосов
/ 02 февраля 2020

Вот вам go:


\i tmp.sql

CREATE TABLE tree_node (
    id serial primary key
    , name varchar
    , parent_id integer references tree_node (id)
);


INSERT INTO tree_node(name, parent_id) VALUES
        ( 'Node-A', NULL)
        , ( 'Node-A.1', 1)
        , ( 'Node-A.1.1', 2)
        ;
SELECT * FROM tree_node;

        -- Find the top value of the sequence
        -- and use it as an increment on all the copies
WITH top(val) AS
        (select currval('tree_node_id_seq')
        )
INSERT INTO tree_node(id, name, parent_id)
SELECT id+top.val
        , name|| '(copy)'
        , parent_id + top.val
FROM tree_node
CROSS JOIN top
        ;

SELECT * FROM tree_node;

        -- bump the sequence
WITH nxt AS (
        select max(id) mx from tree_node
        )
SELECT setval('tree_node_id_seq', (select mx FROM nxt) )
        ;

Вывод:


DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 3
 id |    name    | parent_id 
----+------------+-----------
  1 | Node-A     |          
  2 | Node-A.1   |         1
  3 | Node-A.1.1 |         2
(3 rows)

INSERT 0 3
 id |       name       | parent_id 
----+------------------+-----------
  1 | Node-A           |          
  2 | Node-A.1         |         1
  3 | Node-A.1.1       |         2
  4 | Node-A(copy)     |          
  5 | Node-A.1(copy)   |         4
  6 | Node-A.1.1(copy) |         5
(6 rows)

 setval 
--------
      6
(1 row)
...