项目中,经常会碰到多级的树形结构数据,如地区信息,省、市、区、街道等,或客户关系信息上三级,下三级等。

实际项目中,我们可能碰到以下两种需求:

  • 一条记录中呈现路径:省 - 市 - 区 - 街道
  • 一条记录中呈现上几级:上级,上上级,上上上级

此情此景,使用 WITH RECURSIVE 递归查询再合适不过。

递归查询

在介绍 WITH RECURSIVE 之前,我们先介绍一个 WITH

通过 WITH ,我们可以在写查询语句之前,为一个需要用到的子查询定义一个临时的别名,该别名可以查询语句中使用,从而简化查询语句。如下示例:

WITH 临时别名 AS(
SELECT 1 a, 2 b, 3 c
)
-- 下边是查询语句,像使用表或视图一样使用了“临时别名”
select a * a, b * b, c * c from 临时别名;

接下来我们再来看递归 RECURSIVE ,我们知道,递归形式上就是自己会调用自己,对于数据集而言,递归通常需要两个条件:

  1. 有入口数据,即递归开始的数据记录
  2. 有递归结束的条件,即在关联自己的同时有终止的条件

这第 2 点,原因很简单,关联自己产生的新数据记录又会成为递归关联中的数据。通常 WHERE 子句给出这个条件。

PostgreSQL 中,WITH RECURSIVE 即表示递归查询,“临时别名”在定义自身的子查询体中也可以使用。

我们来看一个示例:

-- 定义了一个临时别名 cet
WITH RECURSIVE cet AS (
-- 递归初始的数据,id=1, name="name 1", pid=null (最顶层父id为空)
SELECT 1 AS id, 'name 1' AS name, cast(null AS int) AS pid
UNION ALL
-- 联合 cet 自己,id 递增,结束条件为 id < 10。如果不加这个 WHERE 会如何?
SELECT id+1, 'name ' || (id+1), id FROM cet WHERE id < 10
)
SELECT * FROM cet;

输出以下结果:

搞定需求

上边的示例中的结果集就是一个典型的树形层级结构,我们以这个数据结果为例来完成文章开头提到的两个需求,首先我们把这个结果集变成一个视图以便当源数据用。

-- 创建一个名字为 view_tree_test 的视图
CREATE VIEW view_tree_test as
WITH RECURSIVE cet AS (
SELECT 1 AS id, 'name 1' AS name, cast(null AS int) AS pid
UNION ALL
SELECT id+1, 'name ' || (id+1), id FROM cet WHERE id < 10
)
SELECT * FROM cet;

我们以 view_tree_test 作为数据源来完成两大需求。

需求一,显示路径

WITH RECURSIVE tpath AS(
SELECT id, name, pid, name as path from view_tree_test where pid is null
UNION ALL
-- 联合子节点
SELECT a.id, a.name, a.pid,
tpath.path || '-' || a.name -- 父路径拼接当前节点名称形成路径
FROM view_tree_test a, tpath -- 关联已有结果,查询其子节点
WHERE a.pid = tpath.id
)
SELECT * FROM tpath;

查询结果可见其效果:

需求二,显示每第记录的上三级

WITH RECURSIVE uuup AS(
-- 初始值,顶层的上级均置为空,需要几级置几个空
SELECT id, name, '' 上级, '' 上上级, '' 上上上级 from view_tree_test where pid is null
UNION ALL
-- 联合子节点
SELECT a.id, a.name,
-- 父级即为上级,父的上级为上上级
uuup.name 上级, uuup.上级 上上级, uuup.上上级 上上上级
FROM view_tree_test a, uuup -- 关联已有结果,查询其子节点
WHERE a.pid = uuup.id
)
SELECT * FROM uuup;

顺利呈现相关的上三级,需要更多上级也是 SO EASY!

小结

PostgreSQL 提供了相当多实用的数据处理方式,让数据处理起来很是便捷。树形结构是应用中经常会使用到,使用递归查询能方便的处理跨层级的计算,还有很多想象空间哦。

PostgreSQL 务实应用(一/5)树形层级的更多相关文章

  1. PostgreSQL 务实应用(四/5)JSON

    JSON 可谓风靡互联网,在数据交换使用上,其优势特别明显,其结构简洁.可读易读.形式灵活.很多 API 接口的数据都采用 JSON 来表示. PostgreSQL 对 JSON 提供了良好的支持.具 ...

  2. PostgreSQL 务实应用(五/5)常用表达

    在实际应用中,对于具体的数据计算我们会找相应的函数来实现.而计算需求不同的表达,往往会使得我们使用不同的函数或方式来实现.或者也可以说,同一计算可以使用多种不同的表达方式实现. PostgreSQL ...

  3. PostgreSQL 务实应用(三/5)分表复制

    问题的提出 在项目中,有些表的记录增长非常快,记录数过大时会使得查询变得困难,导致整个数据库处理性能下降.此时,我们会考虑按一定的规则进行分表存储. 常用的分表方式是按时间周期,如每月一张,每天一张等 ...

  4. 多层级Spinner列表选项实时更新树形层级(选择城市)

    package com.example.spinnerdemo; import android.os.Bundle; import android.app.Activity; import andro ...

  5. PostgreSQL 务实应用(二/5)插入冲突

    在项目中,有时会动态地按周期(如按月)封存统计数据,通常需要做这样的处理: 以按月封存为例,当月数据到达时,先需要检查该月是否有过记录,有则以更新的方式累加统计数字,无则添加一条记录. 假设我们创建以 ...

  6. 路径字符串数据转化为树型层级对象,path to json tree

    由于项目中使用了react 及 ant-design ,在使用tree树型控件时,需要 类似下面的数据, const treeData = [{ title: '0-0', key: '0-0', c ...

  7. Python-模块

    一.模块(modue)的概念: 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样, ...

  8. Java中的访问控制权限

    简介 Java中为什么要设计访问权限控制机制呢?主要作用有两点: (1)为了使用户不要触碰那些他们不该触碰的部分,这些部分对于类内部的操作时必要的,但是它并不属于客户端程序员所需接口的一部分. (2) ...

  9. python--常见模块

    本节大纲: 1.模块介绍 2.time&datetime 3.random. 4.os 5.sys 6.shutil 7.json&picle 8.shelve 9.xml处理 10. ...

随机推荐

  1. longestIncreasingSequence最长上升子序列问题

    package dp; /** * 最长上升子序列问题 */ public class LongestIncreasingSubsequence { /** * 原始dp * @param arr * ...

  2. ORACLE 查看表结构

    select table_name from user_tables; //当前用户的表 select table_name from all_tables; //所有用户的表 select tabl ...

  3. MySQL 存储过程 (2)

    通过存储过程查询数据库返回条数操作 第一步:登录自定义用户建立存储过程需要调用测试用到的student表,具体操作如下 (1) 登录用户

  4. js 中常用的正则表达式

    主要有以下几种: 匹配中文字符的正则表达式: [\u4e00-\u9fa5] 评注:匹配中文还真是个头疼的事,有了这个表达式就好办了哦 获取日期正则表达式:\d{4}[年|\-|\.]\d{1,2}[ ...

  5. 活动推荐 | 听说 PHP 是最好的语言 - 和 OneAPM 一起參与上海 PHPCon 技术盛宴吧

    2015年7月11日,第三届 PHP 大会就要和各位 PHPer 正式见面了.本年度,由 Think 技术社区主办,OneAPM 赞助的 PHPCon2015 是为全部热爱技术的 PHPer 提供的最 ...

  6. 【智能无线小车系列十】通过USB摄像头实现网络监控功能

    如果仅有静态图像可能还不足以满足我们的需求,我们可能会需要用到实时的监控功能.这里介绍一款小应用:motion.motion的功能可强大了,不仅可以将监控的画面通过视频传输,实时展现,更为强大的是,m ...

  7. [IR课程笔记]概率检索模型

    几个符号意义: R:相关文档集 NR:不相关文档集 q:用户查询 dj:文档j 1/0风险情况 PRP(probability ranking principle):概率排序原理,利用概率模型来估计每 ...

  8. linux host=${host:-"localhost"}使用方法

    localhost=${host:-"localhost"} host 变量未设定或者为空,host取"-"后面的值;否则host=$host host=${h ...

  9. AndroidPageObjectTest_Chained.java

    以下代码使用ApiDemos-debug.apk进行测试 //这个脚本用于演示PageFactory的功能:链式注解@AndroidFindBys.@IOSFindBys.具体用法参考页面类的代码. ...

  10. vue定义全局变量和全局方法

    一.全局引入文件 1.先定义共用组件 common.vue <script type="text/javascript"> // 定义一些公共的属性和方法 const ...