Я использую PostgreSQL 9.5, и у меня есть таблица, представляющая дерево:
CREATE TABLE tree (
dependent CHAR(1) NOT NULL,
prereq CHAR(1) NOT NULL,
PRIMARY KEY (dependent, prereq),
CHECK (dependent != prereq)
);
INSERT INTO tree VALUES
('B', 'A'),
('C', 'B'),
('F', 'D'),
('F', 'E'),
('G', 'E'),
('H', 'F'),
('H', 'G'),
('J', 'I'),
('K', 'I'),
('K', 'L'),
('N', 'J'),
('N', 'M'),
('P', 'O'),
('Q', 'P');
Каждая строка в tree
определяет ребро между dependent
узлом, которое зависит от предварительного условия (prereq
) узел.Когда все предпосылки зависимого лица удалены, зависимый перестает существовать.(Чтобы было понятно, циклы не допускаются.) Я буду ссылаться на любой узел без каких-либо предварительных условий, только на иждивенцев, как корневой узел .
Я ищу один SQL-запрос, которыйс учетом списка корневых узлов, подлежащих удалению, даст полный набор узлов, которые будут удалены из дерева.Я только когда-либо удаляю корневые узлы.Например, если бы я должен был удалить корневые узлы A, D, E и I, полный набор узлов, которые нужно удалить, - это A, B, C, D, E, F, G, H, I и J. Вотиллюстрация этого:
Корневые узлы, заштрихованные красным, находятся в исходном списке узлов, которые должны быть удалены.Узлы с красными границами и буквами - это узлы, которые удаляются в результате удаления всех их обязательных узлов.
Я довольно близко подошел к этому запросу:
WITH RECURSIVE deletion AS (
SELECT
tree.*
FROM
tree
WHERE
prereq IN ('A', 'D', 'E', 'I')
UNION
SELECT
tree.*
FROM
deletion
JOIN tree ON tree.prereq = deletion.dependent
)
SELECT prereq FROM deletion
UNION
SELECT dependent FROM deletion
ORDER BY 1
Однако в этом спискеслишком много узлов для удаления:
prereq
--------
A
B
C
D
E
F
G
H
I
J
K
N
(12 rows)
K и N не должны быть в списке, так как они оба имеют обязательные узлы, которые не будут удалены, L и M соответственно.
Что такое один SQL-запрос Я могу использовать в PostgreSQL 9.5, чтобы получить полный список узлов, которые будут удалены при заданном начальном наборе корневых узлов для удаления?
Сколько это стоит, мой настоящийtree
таблица содержит около 100 000 строк.
(у меня есть несколько идей, которые я пока не смог реализовать, например, использование пары вложенных анти-объединений или [ab] с помощью COUNT
как оконная функция, но я еще не взломал это, и я надеюсь, что сообщество может придумать что-то более простое / элегантное.)