Postgre 树状表结构增删改查 递归查询 WITH RECURSIVE

一、简介

当存在层级关系时,通常在设计表结构的时候添加字段parent_id,表示父节点。

树状表的查询不同于常规表,多数情况下查询父节点的数据也要递归查询其子节点,删除父节点也要递归删除子节点。

由于SQL语句的限制,没法直接写递归语句,除非是用函数或存储过程。

POSTGRE数据库引擎提供了WITH   RECURSIVE解决上面的问题。

具体请参考官方资料:https://www.postgresql.org/docs/current/queries-with.html

比如下面的树状结构:

二、WITH

WITH提供了一种编写辅助语句的方法,以便在较大的查询中使用。

这些语句通常被称为公共表表达式(commontableexpression)或cte,

可以被认为是定义仅为一个查询而存在的临时表。

WITH子句中的每个辅助语句都可以是SELECT、INSERT、UPDATE或DELETE;

WITH子句本身附加到主语句,主语句也可以是SELECT、INSERT、UPDATE或DELETE。

比如下面的SQL语句: 

with T as (
    select * from template_info where parent_id=-1
) select * from T

查询出所有一级节点,括号中的语句查出的内容保存在了临时表T中,然后在从T中查询所有。

可以定义多个WITH子句,用逗号分隔开,这样就可以查询多个表,并行查询,然后对临时表集合进行查询统计。

三、RECURSIVE

可选的RECURSIVE递归修饰符从一个简单的语法改变为一个特性,它可以完成标准SQL中不可能完成的事情。

使用递归,WITH查询可以引用自己的输出。

with RECURSIVE t as 
        (select * from template_info where id =18
         union all
         (select d.* from t inner join template_info d on t.id=d.parent_id)
        ) select * from t

查询的逻辑是:

1、计算非递归项,也就是 select * from template_info where id =18,这一行查出的是根节点,将结果存在临时表B中;

2、计算递归项,也就是 select d.* from t inner join template_info d on t.id=d.parent_id,将临时表B与 template_info进行连接查询得到C,将BC合并得到D;

3、一直计算递归项,并合并结果集,直到所有C为空,结束迭代过程;

4、查询结果集得到最终结果。

注:严格地说,这个过程是迭代而不是递归,但是递归是SQL标准委员会选择的术语。

 步骤进一步拆解:

1、查询一个

 select * from template_info where id =18

 2、合并

    with RECURSIVE t as 
        (select * from template_info where id =18
         union 
         (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=18)
        ) select * from t 

 3、再合并

复制代码

    with RECURSIVE t as 
        (select * from template_info where id =18
         union 
         (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=18)
        ) select * from t union (
            with RECURSIVE t2 as 
        (
         (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=19)
        ) select * from t2
        ) 

复制代码

4、再合并,没有了,结束查询。

复制代码

    with RECURSIVE t as 
        (select * from template_info where id =18
         union 
         (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=18)
        ) select * from t union (
            with RECURSIVE t2 as 
        (
         (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=20)
        ) select * from t2
        ) 

复制代码

 四、WITH中UPDATE

WITH t AS (
    UPDATE products SET price = price * 1.05
    RETURNING *
)
SELECT * FROM t;

五、WITH中DELETE和INSERT

这个查询实际上从products把行移动到products_logWITH中的DELETE删除来自products的指定行,

以它的RETURNING子句返回它们的内容,并且接着主查询读该输出并将它插入到products_log

复制代码

WITH moved_rows AS (
    DELETE FROM products
    WHERE
        "date" >= '2010-10-01' AND
        "date" < '2010-11-01'
    RETURNING *
)
INSERT INTO products_log
SELECT * FROM moved_rows;

复制代码

猜你喜欢

转载自blog.csdn.net/u014556081/article/details/113185656