【问题标题】:Recursive delete of multiple rows in one table递归删除一张表中的多行
【发布时间】:2020-03-04 21:34:47
【问题描述】:

我的 postgres 数据库有问题。我有一个表 Tasks 有 3 列:ID、Name 和 Parent_ID(指的是该表中的另一个任务 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,并删除它的所有孩子和孩子的所有孩子等等。(在这种情况下,B 和 D,以及作为 B 的孩子的 C 被删除)类似级联删除的东西,但我不能这样做。也许任何功能都可以工作?

删除后的结果应该是

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

希望你们能帮助我。

【问题讨论】:

    标签: sql database postgresql sql-delete recursive-query


    【解决方案1】:

    您可以使用递归查询从起始名称构建所有后代行的列表,然后将其用作删除的过滤器。

    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)
    

    Demo on DB Fiddle - 执行查询后的表格内容:

    编号 |姓名 | parent_id -: | :--- | --------: 5 | E | 0 6 | F | 0

    【讨论】:

    • 它工作正常,谢谢,但是如果将 ID 作为外键放在另一个表中怎么办?它禁止我删除,因为它违反了另一个表的外键(我也想从这个表中删除这些行)。准确地说,第二张表包含用于某些任务的材料。因此,第二个表中的每个任务 ID 在一行中都有自己的材料。我尝试进行事务处理,或者一次删除后一次删除,甚至尝试以某种方式加入这两个表,但它不起作用。
    • @fufuj:您需要先从子表中删除,然后再从主表中删除。您可以使用相同的查询,只需在最后的delete 语句中更改目标表和列名:delete from << mytable >> where << id >> in (select id from cte)
    【解决方案2】:

    您只需要一个级联 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)
    

    【讨论】:

      【解决方案3】:

      使用递归 cte 获取 Name = 'A' 的所有行及其下属。 然后从表 employees 中删除它。

      创建表的步骤如下:

      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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多