SQL 展现父子关系

SQL 展现父子关系,你想找出子节点对应的父节点信息。例如,你希望显示每个员工及其管理者的名字。你希望返回的结果集如下所示。

SQL 展现父子关系 问题描述

你想找出子节点对应的父节点信息。例如,你希望显示每个员工及其管理者的名字。你希望返回的结果集如下所示。

EMPS_AND_MGRS
------------------------------
FORD works for JONES
SCOTT works for JONES
JAMES works for BLAKE
TURNER works for BLAKE
MARTIN works for BLAKE
WARD works for BLAKE
ALLEN works for BLAKE
MILLER works for CLARK
ADAMS works for SCOTT
CLARK works for KING
BLAKE works for KING
JONES works for KING
SMITH works for FORD

SQL 展现父子关系 解决方案

基于 MGREMPNOEMP 表做自连接查询,找出每个员工的管理者的名字。然后使用数据库提供的字符串连接函数生成符合要求的字符串。
DB2、Oracle 和 PostgreSQL
自连接 EMP 表。然后使用双竖线||连接字符串。

1 select a.ename || ' works for ' || b.ename as emps_and_mgrs
2   from emp a, emp b
3  where a.mgr = b.empno

MySQL
自连接 EMP 表,然后使用 CONCAT 函数连接字符串。

1 select concat(a.ename, ' works for ',b.ename) as emps_and_mgrs
2   from emp a, emp b
3  where a.mgr = b.empno

SQL Server
自连接 EMP 表,然后使用加号“+”连接字符串。

1 select a.ename + ' works for ' + b.ename as emps_and_mgrs
2   from emp a, emp b
3  where a.mgr = b.empno

SQL 展现父子关系 扩展知识

以上所有解决方案的实现思路大致相同。不同之处仅在于字符串连接的方式,所以下面的讨论能够兼顾到所有的解决方案,不用再一一解释每一个具体的做法。
基于 MGREMPNO 的连接查询是关键所在。首先通过自连接 EMP 表创建一个笛卡儿积(下面只显示了笛卡儿积返回值的一部分)。

select a.empno, b.empno
  from emp a, emp b
 
EMPNO        MGR
----- ----------
 7369       7369
 7369       7499
 7369       7521
 7369       7566
 7369       7654
 7369       7698
 7369       7782
 7369       7788
 7369       7839
 7369       7844
 7369       7876
 7369       7900
 7369       7902
 7369       7934
 7499       7369
 7499       7499
 7499       7521
 7499       7566
 7499       7654
 7499       7698
 7499       7782
 7499       7788
 7499       7839
 7499       7844
 7499       7876
 7499       7900
 7499       7902
 7499       7934

如上所示,笛卡儿积返回了每一种可能的 EMPNO/EMPNO 组合。(这样看起来所有人都是 EMPNO 7369 的管理者,甚至也包括 7369 本人。)
下一步要过滤结果集,以便只返回每个员工及其管理者的 EMPNO。增加 MGREMPNO 相等的判断条件即可。

1 select a.empno, b.empno mgr
2    from emp a, emp b
3   where a.mgr = b.empno
 
     EMPNO        MGR
---------- ----------
      7902       7566
      7788       7566
      7900       7698
      7844       7698
      7654       7698
      7521       7698
      7499       7698
      7934       7782
      7876       7788
      7782       7839
      7698       7839
      7566       7839
      7369       7902

现在已经得到了每个员工及其管理者的 EMPNO,接下来只要查询 B.ENAME 提取出每个管理者的名字即可。如果你还没有完全理解本解决方案的原理,那么可以先忽略自连接方案,转而尝试下面的标量子查询方案。

select a.ename,
       (select b.ename
          from emp b
         where b.empno = a.mgr) as mgr
  from emp a
 
ENAME      MGR
---------- ----------
SMITH      FORD
ALLEN      BLAKE
WARD       BLAKE
JONES      KING
MARTIN     BLAKE
BLAKE      KING
CLARK      KING
SCOTT      JONES
KING
TURNER     BLAKE
ADAMS      SCOTT
JAMES      BLAKE
FORD       JONES
MILLER     CLARK

上述标量子查询方案实际上等价于自连接方案,只有一行数据除外:员工 KING 出现在了结果集里,而自连接方案的查询结果里却不包括该员工。你可能会问:“为什么不会包括?”注意,Null 不等于任何值,甚至不等于它自身。在自连接解决方案中,我们基于 EMPNOMGR 做相等连接查询(equi-join),这就剔除了 MGR 值等于 Null 的员工。如果既使用自连接方案,又希望员工 KING 出现在最终的结果集里,就必须使用外连接,就像下面的两种查询那样。第一种解决方案使用了 ANSI 外连接,第二种则用了 Oracle 的外连接语法。这两种解决方案的结果自然是相同的,我们把输出结果放在了第二个方案的后面。

/* ANSI */
select a.ename, b.ename mgr
  from emp a left join emp b
    on (a.mgr = b.empno)
 
/* Oracle */
select a.ename, b.ename mgr
  from emp a, emp b
 where a.mgr = b.empno (+)
 
ENAME      MGR
---------- ----------
FORD       JONES
SCOTT      JONES
JAMES      BLAKE
TURNER     BLAKE
MARTIN     BLAKE
WARD       BLAKE
ALLEN      BLAKE
MILLER     CLARK
ADAMS      SCOTT
CLARK      KING
BLAKE      KING
JONES      KING
SMITH      FORD
KING

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程