资讯专栏INFORMATION COLUMN

PostgreSQL:递归查询应用场景

YJNldm / 2774人阅读

摘要:今天在坛子里有人提出了一个问题,问题是这样的在以下指定表中中国辽宁山东沈阳大连济南和平区沈河区现在给定一个号,想得到它完整的名字。递归往上找,直到为止。也就是最高层级时结束,求完整语句。

今天在坛子里有人提出了一个问题,问题是这样的:在以下指定表中

id name fatherid
1 中国 0
2 辽宁 1
3 山东 1
4 沈阳 2
5 大连 2
6 济南 3
7 和平区 4
8 沈河区 4

现在给定一个id号,想得到它完整的名字。如:
当id=7时,名字是:中国辽宁沈阳和平区
当id=5时,名字是:中国辽宁大连

id是任意给定的,不确定在哪一层。递归往上找,直到 fatherid=0 为止。也就是最高层级时结束,
求完整SQL语句。

看到这个问题,第一想到的是可以用 PG的递归查询实现,之前也写过类似的例子,
http://francs3.blog.163.com/b...,但之前的例子
是向下递归,而这里的需求是向上递归,略有不同,于是忍不住演示下:

这个问题的思路是分两步走,第一步:查询出指定节点的父节点;第二步:将查询出的所有父节点排列到一行。

--1 创建测试表,并插入测试数据

skytf=> create table test_area(id int4,name varchar(32),fatherid int4);
CREATE TABLE

insert into test_area values (1, "中国"   ,0);
insert into test_area values (2, "辽宁"   ,1);
insert into test_area values (3, "山东"   ,1);
insert into test_area values (4, "沈阳"   ,2);
insert into test_area values (5, "大连"   ,2);
insert into test_area values (6, "济南"   ,3);
insert into test_area values (7, "和平区" ,4);
insert into test_area values (8, "沈河区" ,4);
skytf=> select * From test_area;
 id |  name  | fatherid 
----+--------+----------
  1 | 中国   |        0
  2 | 辽宁   |        1
  3 | 山东   |        1
  4 | 沈阳   |        2
  5 | 大连   |        2
  6 | 济南   |        3
  7 | 和平区 |        4
  8 | 沈河区 |        4
(8 rows)

--2 查询指定节点以下的所有节点

  WITH RECURSIVE r AS ( 

       SELECT * FROM test_area WHERE id = 4 
     union   ALL 
       SELECT test_area.* FROM test_area, r WHERE test_area.fatherid = r.id 
     ) 
SELECT * FROM r ORDER BY id;
 id |  name  | fatherid 
----+--------+----------
  4 | 沈阳   |        2
  7 | 和平区 |        4
  8 | 沈河区 |        4
(3 rows)

备注:通常的用法是查询指定节点以及指定节点以下的所有节点,那么本贴的需求刚好相反,需要查询指定节点以上的所有节点。

--3 查询指定节点以上的所有节点

 WITH RECURSIVE r AS ( 
       SELECT * FROM test_area WHERE id = 4 
     union   ALL 
       SELECT test_area.* FROM test_area, r WHERE test_area.id = r.fatherid 
     ) 
 SELECT * FROM r ORDER BY id;

 id | name | fatherid 
----+------+----------
  1 | 中国 |        0
  2 | 辽宁 |        1
  4 | 沈阳 |        2
(3 rows)

备注:这正是我们想要的结果,接下来需要将 name 字段结果集合并成一行,我这里想到的是创建个 function,当然也有其它方法。

--4 create funcion

CREATE or replace FUNCTION func_get_area(in in_id int4, out o_area text)  AS 

$$ 
DECLARE
   v_rec_record RECORD;
BEGIN

  o_area = "";
  FOR v_rec_record IN (WITH RECURSIVE r AS (SELECT *
                           FROM test_area
                          WHERE id = in_id
                         union ALL
                         SELECT test_area.*
                           FROM test_area, r
                          WHERE test_area.id = r.fatherid)SELECT name
                         FROM r
                        ORDER BY id) LOOP
    o_area := o_area || v_rec_record.name;
  END LOOP;
  return;
END; 
$$
LANGUAGE "plpgsql";

备注:函数的作用为拼接 name 字段。

--5 测试

 skytf=> select func_get_area(7) ;
   func_get_area    
--------------------
 中国辽宁沈阳和平区
(1 row)

skytf=> select func_get_area(5) ;
 func_get_area 
---------------
 中国辽宁大连
(1 row)

备注:正好实现了需求,当表数据量较大时,考虑到性能,建议在表 test_area 字段 id,fatherid 上建立多带带的索引。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38974.html

相关文章

  • 我对Postgresql递归查询的理解

    摘要:先声明,瞎猜的,个人理解,不一定对。重复执行步骤和,只是这里执行第步的时候,从中选出的记录为执行第步,就变成了,就变成了找的儿子记录如果第步返回多条记录,类似啦,反正递归嘛如此,自顶向下,一棵树就出来了 先声明,瞎猜的,个人理解,不一定对。 递归查询大家都知道,常见的如一张表,包含id(主键),parent_id(该记录的父亲id),比如我们要从某1个id往下找他所有的儿子还有孙子(这...

    kaka 评论0 收藏0
  • PostgreSQL UDB,让31会议数据管理更高效可靠

    摘要:相比自建,其可靠性更高,方便运维维护。宋体经过审慎考虑,用户同时选用三种数据库,针对性的满足不同目标。宋体宋体其中,相比于在上的快速高效是其优势,也是用户选型的重要砝码。PostgreSQL UDB用在大数据分析上,查询效率更高。相比自建,其可靠性更高,方便运维维护。 — 31会议运维经理 汤雷 如何用好PostgreSQL? PostgreSQL是业内一款十分流行的开源数...

    vspiders 评论0 收藏0
  • 构建可扩展的PostgreSQL解决方案

    摘要:这可以通过负载平衡来实现数据分片当问题不是并发查询的数量,而是数据库的大小和单个查询的速度时,可以实现不同的方法。 showImg(https://segmentfault.com/img/remote/1460000018875091); 来源 | 愿码(ChainDesk.CN)内容编辑 愿码Slogan | 连接每个程序员的故事 网站 | http://chaindesk.cn...

    jonh_felix 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<