Рекурсивное удаление нескольких строк в одной таблице - PullRequest
2 голосов
/ 05 марта 2020

У меня проблема с базой данных postgres. У меня есть таблица Tasks с 3 столбцами: ID, имя и Parent_ID (который ссылается на другой идентификатор задачи в этой таблице):

id | name | parent_id 
---+------+-----------
 1 | A    |     0
 2 | B    |     1
 3 | C    |     2
 4 | D    |     1
 5 | E    |     0
 6 | F    |     0

Так что в основном это так:

1. A
2.     B
3.          C
4.     D
5. E
6. F  

То, что я пытаюсь сделать, это удалить задание A и удалить всех его потомков и всех потомков потомков et c et c .. (в данном случае B и D вместе с C как его потомки B, который удаляется) что-то вроде каскадного удаления, но я не могу это сделать. Может быть, любая функция будет работать?

Результат после удаления должен быть

id | name | parent_id
---+------+-----------
 5 | E    |     0
 6 | F    |     0

Надеюсь, вы, ребята, можете мне помочь.

Ответы [ 3 ]

2 голосов
/ 05 марта 2020

Вам нужно только каскадное FK-ограничение:


\i tmp.sql

CREATE TABLE employees (
   id serial PRIMARY KEY
   , name VARCHAR NOT NULL
   , parent_id INT REFERENCES employees(id) ON DELETE CASCADE
);

INSERT INTO employees
VALUES (1,'A', NULL),(2,'B', 1),(3,'C', 2),
       (4,'D', 1),(5,'E', NULL),(6,'F', NULL);

DELETE FROM employees
WHERE name = 'A'
        ;

SELECT * FROM employees
        ;


----------

Result:

----------

    DROP SCHEMA
    CREATE SCHEMA
    SET
    CREATE TABLE
    INSERT 0 6
    DELETE 1
     id | name | parent_id 
    ----+------+-----------
      5 | E    |          
      6 | F    |          
    (2 rows)
2 голосов
/ 05 марта 2020

Вы можете построить список всех потомков строк из начального имени с помощью рекурсивного запроса, а затем использовать его в качестве фильтра для удалений.

with recursive cte(id, parent_id) as (
    select id, parent_id from mytable where name = 'A'
    union all
    select t.id, t.parent_id from mytable t inner join cte c on c.id = t.parent_id
)
delete from mytable where id in (select id from cte)

Демонстрация в БД Скрипка - содержимое таблицы после выполнения запроса:

id | name | parent_id
-: | :--- | --------:
 5 | E    |         0
 6 | F    |         0
1 голос
/ 05 марта 2020

Используйте рекурсивный cte, чтобы получить все строки с Name = 'A' и его подчиненными. Затем удалите его из таблицы сотрудников.

Вот шаг для создания таблицы:

Sample table: CREATE TABLE employees (
   id serial PRIMARY KEY,
   name VARCHAR NOT NULL,
   parent_id INT
);

INSERT INTO employees 
VALUES (1,'A', 0),(2,'B', 1),(3,'C', 2),
       (4,'D', 1),(5,'E', 0),(6,'F', 0);

Запрос:

WITH RECURSIVE subordinates AS (
   SELECT
      id,
      parent_id,
      name
   FROM
      employees
   WHERE
      name = 'A'
   UNION
      SELECT
         e.id,
         e.parent_id,
         e.name
      FROM
         employees e
      INNER JOIN subordinates s ON s.id = e.parent_id
) 
DELETE 
FROM employees
WHERE id in (
  SELECT
    id
  FROM
   subordinates);

SELECT * FROM employees;
...