【SQL开发实战技巧】系列(三十):数仓报表场景☞树形(分层)查询如何排序?以及如何在树形查询中正确的使用where条件

系列文章目录

【SQL开发实战技巧】系列(一):关于SQL不得不说的那些事
【SQL开发实战技巧】系列(二):简单单表查询
【SQL开发实战技巧】系列(三):SQL排序的那些事
【SQL开发实战技巧】系列(四):从执行计划讨论UNION ALL与空字符串&UNION与OR的使用注意事项
【SQL开发实战技巧】系列(五):从执行计划看IN、EXISTS 和 INNER JOIN效率,我们要分场景不要死记网上结论
【SQL开发实战技巧】系列(六):从执行计划看NOT IN、NOT EXISTS 和 LEFT JOIN效率,记住内外关联条件不要乱放
【SQL开发实战技巧】系列(七):从有重复数据前提下如何比较出两个表中的差异数据及对应条数聊起
【SQL开发实战技巧】系列(八):聊聊如何插入数据时比约束更灵活的限制数据插入以及怎么一个insert语句同时插入多张表
【SQL开发实战技巧】系列(九):一个update误把其他列数据更新成空了?Merge改写update!给你五种删除重复数据的写法!
【SQL开发实战技巧】系列(十):从拆分字符串、替换字符串以及统计字符串出现次数说起
【SQL开发实战技巧】系列(十一):拿几个案例讲讲translate|regexp_replace|listagg|wmsys.wm_concat|substr|regexp_substr常用函数
【SQL开发实战技巧】系列(十二):三问(如何对字符串字母去重后按字母顺序排列字符串?如何识别哪些字符串中包含数字?如何将分隔数据转换为多值IN列表?)
【SQL开发实战技巧】系列(十三):讨论一下常用聚集函数&通过执行计划看sum()over()对员工工资进行累加
【SQL开发实战技巧】系列(十四):计算消费后的余额&计算银行流水累计和&计算各部门工资排名前三位的员工
【SQL开发实战技巧】系列(十五):查找最值所在行数据信息及快速计算总和百之max/min() keep() over()、fisrt_value、last_value、ratio_to_report
【SQL开发实战技巧】系列(十六):数据仓库中时间类型操作(初级)日、月、年、时、分、秒之差及时间间隔计算
【SQL开发实战技巧】系列(十七):数据仓库中时间类型操作(初级)确定两个日期之间的工作天数、计算—年中周内各日期出现次数、确定当前记录和下一条记录之间相差的天数
【SQL开发实战技巧】系列(十八):数据仓库中时间类型操作(进阶)INTERVAL、EXTRACT以及如何确定一年是否为闰年及周的计算
【SQL开发实战技巧】系列(十九):数据仓库中时间类型操作(进阶)如何一个SQL打印当月或一年的日历?如何确定某月内第一个和最后—个周内某天的日期?
【SQL开发实战技巧】系列(二十):数据仓库中时间类型操作(进阶)获取季度开始结束时间以及如何统计非连续性时间的数据
【SQL开发实战技巧】系列(二十一):数据仓库中时间类型操作(进阶)识别重叠的日期范围,按指定10分钟时间间隔汇总数据
【SQL开发实战技巧】系列(二十二):数仓报表场景☞ 从分析函数效率一定快吗聊一聊结果集分页和隔行抽样实现方式
【SQL开发实战技巧】系列(二十三):数仓报表场景☞ 如何对数据排列组合去重以及通过如何找到包含最大值和最小值的记录这个问题再次用执行计划给你证明分析函数性能不一定高
【SQL开发实战技巧】系列(二十四):数仓报表场景☞通过案例执行计划详解”行转列”,”列转行”是如何实现的
【SQL开发实战技巧】系列(二十五):数仓报表场景☞结果集中的重复数据只显示一次以及计算部门薪资差异高效的写法以及如何对数据进行快速分组
【SQL开发实战技巧】系列(二十六):数仓报表场景☞聊聊ROLLUP、UNION ALL是如何分别做分组合计的以及如何识别哪些行是做汇总的结果行
【SQL开发实战技巧】系列(二十七):数仓报表场景☞通过对移动范围进行聚集来详解分析函数开窗原理以及如何一个SQL打印九九乘法表
【SQL开发实战技巧】系列(二十八):数仓报表场景☞人员分布问题以及不同组(分区)同时聚集如何实现
【SQL开发实战技巧】系列(二十九):数仓报表场景☞简单的树形(分层)查询以及如何确定根节点、分支节点和叶子节点
【SQL开发实战技巧】系列(三十):数仓报表场景☞树形(分层)查询如何排序?以及如何在树形查询中正确的使用where条件



前言

本篇文章讲解的主要内容是:第一个案例给大家介绍在树形(分层)查询中,如何通过SIBLINGS关键词进行正确的排序。第二个案例主要介绍树形查询中的WHERE过滤的对象是"树形查询的结果"。这句话是重点!!!!!所以要谨记,如果你有这种过滤+树形查询的需求,一定一定要先过滤,用子查询嵌套一次,再进行树形查询。
【SQL开发实战技巧】这一系列博主当作复习旧知识来进行写作,毕竟SQL开发在数据分析场景非常重要且基础,面试也会经常问SQL开发和调优经验,相信当我写完这一系列文章,也能再有所收获,未来面对SQL面试也能游刃有余~。


一、树形查询中的排序

如果树形查询里直接使用ORDER BY排序会怎样?看下面的示例:

SELECT lpad('->', (level - 1) * 2, '->') || empno AS 员工编码,
       ename AS 姓名,
       mgr AS 主管编码,
       (PRIOR ename) AS 主管姓名,
       level as 级别,
       decode(level, 1, 1) as 根节点,
       decode(connect_by_isleaf, 1, 1) as 叶子节点,
       CASE
         WHEN (connect_by_isleaf = 0 AND LEVEL > 1) THEN
          1
       END AS 分支节点,
       sys_connect_by_path(ename,'->') as enames
  FROM emp
 START WITH empno = 7566
CONNECT BY (PRIOR empno) = mgr
order by empno;


员工编码                                                                         姓名        主管编码 主管姓名           级别        根节点       叶子节点       分支节点 ENAMES
-------------------------------------------------------------------------------- ---------- ----- ---------- ---------- ---------- ---------- ---------- --------------------------------------------------------------------------------
->->7369                                                                         SMITH       7902 FORD                3                     1            ->JONES->FORD->SMITH
7566                                                                             JONES       7839                     1          1                       ->JONES
->7788                                                                           SCOTT       7566 JONES               2                                1 ->JONES->SCOTT
->->7876                                                                         ADAMS       7788 SCOTT               3                     1            ->JONES->SCOTT->ADAMS
->7902                                                                           FORD        7566 JONES               2                                1 ->JONES->FORD

从上面的结果可以看到,数据都乱了,上下级关系已经完全乱了。而对于树形数据,我们需要的应该是只对同一分支下的数据排序,此时就要用到专用关键字"SIBLINGS":

SELECT lpad('->', (level - 1) * 2, '->') || empno AS 员工编码,
       ename AS 姓名,
       mgr AS 主管编码,
       (PRIOR ename) AS 主管姓名,
       level as 级别,
       decode(level, 1, 1) as 根节点,
       decode(connect_by_isleaf, 1, 1) as 叶子节点,
       CASE
         WHEN (connect_by_isleaf = 0 AND LEVEL > 1) THEN
          1
       END AS 分支节点,
       sys_connect_by_path(ename,'->') as enames
  FROM emp
 START WITH empno = 7566
CONNECT BY (PRIOR empno) = mgr
order siblings by  empno;

员工编码                                                                         姓名        主管编码 主管姓名           级别        根节点       叶子节点       分支节点 ENAMES
-------------------------------------------------------------------------------- ---------- ----- ---------- ---------- ---------- ---------- ---------- --------------------------------------------------------------------------------
7566                                                                             JONES       7839                     1          1                       ->JONES
->7788                                                                           SCOTT       7566 JONES               2                                1 ->JONES->SCOTT
->->7876                                                                         ADAMS       7788 SCOTT               3                     1            ->JONES->SCOTT->ADAMS
->7902                                                                           FORD        7566 JONES               2                                1 ->JONES->FORD
->->7369                                                                         SMITH       7902 FORD                3                     1            ->JONES->FORD->SMITH

可以看到,这个语句只对同一分支empno = 7566的(7788,7902)进行排序,而没有影响到树形结构。

二、如何在树形查询中正确的添加WHERE条件

现在有个需求:如果限定只对部门20的人员进行树形查询?
怎么做呢?估计很多人会直接在WHERe后加条件,如下:

SELECTempnoAS员工编码,mgr	AS主管编码,enarneAS姓名,deptnoAS部门编码
FROMemp
WHEREdeptno=20
STARTWITHmgrISNULL
CONNECTBY(PRIORempno)=mgr;
SELECT lpad('->', (level - 1) * 2, '->') || empno AS 员工编码,
       ename AS 姓名,
       mgr AS 主管编码,
       (PRIOR ename) AS 主管姓名,
       level as 级别,
       decode(level, 1, 1) as 根节点,
       decode(connect_by_isleaf, 1, 1) as 叶子节点,
       CASE
         WHEN (connect_by_isleaf = 0 AND LEVEL > 1) THEN
          1
       END AS 分支节点,
       deptno as 部门编码,
       sys_connect_by_path(ename,'->') as enames
  FROM emp
   where deptno=20
 START WITH mgr is null
CONNECT BY (PRIOR empno) = mgr
order siblings by  empno;
员工编码                                                                         姓名        主管编码 主管姓名           级别        根节点       叶子节点       分支节点 部门编码 ENAMES
-------------------------------------------------------------------------------- ---------- ----- ---------- ---------- ---------- ---------- ---------- ---- --------------------------------------------------------------------------------
->7566                                                                           JONES       7839 KING                2                                1   20 ->KING->JONES
->->7788                                                                         SCOTT       7566 JONES               3                                1   20 ->KING->JONES->SCOTT
->->->7876                                                                       ADAMS       7788 SCOTT               4                     1              20 ->KING->JONES->SCOTT->ADAMS
->->7902                                                                         FORD        7566 JONES               3                                1   20 ->KING->JONES->FORD
->->->7369                                                                       SMITH       7902 FORD                4                     1              20 ->KING->JONES->FORD->SMITH

SQL> 

上面的结果咱们先不分析,我们先回头看看emp表原来数据是什么样的:

SQL> select * from emp;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7369 SMITH      CLERK      7902 1980-12-17     800.00               20
 7499 ALLEN      SALESMAN   7698 1981-2-20     1600.00    300.00     30
 7521 WARD       SALESMAN   7698 1981-2-22     1250.00    500.00     30
 7566 JONES      MANAGER    7839 1981-4-2      2975.00               20
 7654 MARTIN     SALESMAN   7698 1981-9-28     1250.00   1400.00     30
 7698 BLAKE      MANAGER    7839 1981-5-1      2850.00               30
 7782 CLARK      MANAGER    7839 1981-6-9      2450.00               10
 7788 SCOTT      ANALYST    7566 1987-4-19     3000.00               20
 7839 KING       PRESIDENT       1981-11-17    5000.00               10
 7844 TURNER     SALESMAN   7698 1981-9-8      1500.00      0.00     30
 7876 ADAMS      CLERK      7788 1987-5-23     1100.00               20
 7900 JAMES      CLERK      7698 1981-12-3      950.00               30
 7902 FORD       ANALYST    7566 1981-12-3     3000.00               20
 7934 MILLER     CLERK      7782 1982-1-23     1300.00               10

14 rows selected

从上面emp表数据我们可以看到,deptno=20的员工中,压根就没有 mgr is null的数据,那根节点条件都为“假”,那哪来的树形结构?
所以说前面的树形查询这个结果明显不对,因为部门20不存在mgr为空的数据,那么也就不该返回数据。
下面我将emp表先进行where deptno = 20的过滤,然后在进行树形结构的查询。看下面的查询结果,然后与上面的查询做个对比:

SQL> SELECT lpad('->', (level - 1) * 2, '->') || empno AS 员工编码,
  2         ename AS 姓名,
  3         mgr AS 主管编码,
  4         (PRIOR ename) AS 主管姓名,
  5         level as 级别,
  6         decode(level, 1, 1) as 根节点,
  7         decode(connect_by_isleaf, 1, 1) as 叶子节点,
  8         CASE
  9           WHEN (connect_by_isleaf = 0 AND LEVEL > 1) THEN
 10            1
 11         END AS 分支节点,
 12         deptno as 部门编码,
 13         sys_connect_by_path(ename, '->') as enames
 14    FROM (select * from emp where deptno = 20)
 15   START WITH mgr is null
 16  CONNECT BY (PRIOR empno) = mgr
 17   order siblings by empno;

员工编码                                                                         姓名        主管编码 主管姓名           级别        根节点       叶子节点       分支节点 部门编码 ENAMES
-------------------------------------------------------------------------------- ---------- ----- ---------- ---------- ---------- ---------- ---------- ---- --------------------------------------------------------------------------------

SQL> 

这个语句没有返回数据。原因是树形查询中的WHERE过滤的对象是"树形查询的结果"。这句话是重点!!!!!所以要谨记,如果你有这种过滤+树形查询的需求,一定一定要先过滤,用子查询嵌套一次,再进行树形查询。


总结

本篇文章讲解的主要内容是:第一个案例给大家介绍在树形(分层)查询中,如何通过SIBLINGS关键词进行正确的排序。第二个案例主要介绍树形查询中的WHERE过滤的对象是"树形查询的结果"。这句话是重点!!!!!所以要谨记,如果你有这种过滤+树形查询的需求,一定一定要先过滤,用子查询嵌套一次,再进行树形查询。

猜你喜欢

转载自blog.csdn.net/qq_28356739/article/details/129847900