前面咱们写了一下 SQL 的极简入门,今天来讲点高级查询。没看到的朋友能够点击下面连接查看。
1 小时 SQL 极速入门(一)
1 小时 SQL 极速入门(二)
1 小时 SQL 极速入门(三)sql
层次化结构能够理解为树状数据结构,由节点构成。好比常见的组织结构由一个总经理,多个副总经理,多个部门部长组成。再好比在生产制造中一件产品会有多个子零件组成。举个简单的例子,以下图所示数据库
汽车做为根节点,下面包含发动机和车身两个子节点,而子节点又是由其余叶节点构成。(叶节点表示没有子节点的节点)数据结构
假如咱们要把这些产品信息存储到数据库中,会造成以下数据表。code
咱们用 parent_product_id 列表示当前产品的父产品是哪个。blog
那么用 SQL 语句如何进行层次化查询呢?这里就要用到 CONNECT BY 和 START WITH 语法。
咱们先把 SQL 写出来,再来解释其中的含义。递归
SELECT level, id, parent_product_id, name FROM product START WITH id = 1 CONNECT BY prior id = parent_product_id ORDER BY level
查询结果以下:get
解释一下:LEVEL 列表示当前产品属于第几层级。START WITH 表示从哪个产品开始查询,CONNECT BY PRIOR 表示父节点与子节点的关系,每个产品的 ID 指向一个父产品。产品
若是咱们把 START WITH 的查询起点改成 id = 2,从新运行上面的 SQL 语句将会获得以下结果:io
由于 id=2 的产品是车身,咱们就只能查到车身下面的子产品。入门
固然,咱们能够把查询结果美化一下,使其更有层次感,咱们让根节点下面的 LEVEL 前面加几个空格便可。把上面的 SQL 稍微修改一下。为每一个 LEVEL 前面增长 2*(LEVEL-1)个空格,这样第二层就会增长两个空格,第三层会增长四个空格。
SELECT level, id, parent_product_id, LPAD(' ', 2 * (level - 1)) || name AS name FROM product START WITH id = 1 CONNECT BY prior id = parent_product_id
查询结果已经有了层次感,以下图:
除了使用上面咱们说的方法,还可使用递归查询获得一样的结果。递归会用到 WITH 语句。普通的 WITH 语句能够看做一个子查询,咱们在 WITH 外部能够直接使用这个子查询的内容。
当递归查询时,咱们是在 WITH 语句内部来引用这个子查询。仍是上面的例子,咱们使用 WITH 语句来查询。
WITH temp_product (product_level, id, parent_product_id,name) AS ( SELECT 0 AS product_level,id,parent_product_id,name FROM product WHERE parent_product_id IS NULL UNION ALL SELECT tp.product_level + 1,p.id, p.parent_product_id, p.name FROM product p JOIN temp_product tp ON p.parent_product_id=tp.id ) SELECT product_level, id, parent_product_id, LPAD(' ', 2 * product_level) || name AS NAME FROM temp_product;
第一条 SELECT 语句咱们查询出来了根节点,而且设置为 level = 0,第二条SELECT 语句关联上 WITH 语句自身,而且 level 每层加 1 进行递归。
查询结果以下:
能够看到第一列是展现的产品层级,和咱们上面查询出来的结果是一致的。
同时使用 WITH 递归时还可使用深度优先搜索和广度优先搜索,什么意思呢?广度优先就是在返回子行以前首先返回兄弟行,如上图,首先把车身和发动机两个兄弟行返回,以后是他们下面的子行。相反,深度优先就是首先返回一个父节点的子行再返回另外一个兄弟行。
咱们只须要在 SELECT 语句上方加上下面语句便可实现深度优先搜索查询。
search depth FIRST BY id SET order_by_id
结果以下,看到首先返回每一个父节点下的子行,再返回另外一个父节点。
同理,广度优先使用的是下面的 SQL 语句
search breadth FIRST BY id SET order_by_id