昨天CSDN里处理问题的时候,发现了一个语法connect_by_root,眼前一亮,好像没有见过,经常用的只是connect by ,于是翻开文档重新学习了下
先看自带的SCHEMA的SCOTT的数据:
SQL>SELECT e.empno,e.ename,e.mgr,e.deptno FROM emp e;
EMPNO | ENAME | MGR | DEPTNO |
7369 | SMITH | 7902 | 20 |
7499 | ALLEN | 7698 | 30 |
7521 | WARD | 7698 | 30 |
7566 | JONES | 7839 | 20 |
7654 | MARTIN | 7698 | 30 |
7698 | BLAKE | 7839 | 30 |
7782 | CLARK | 7839 | 10 |
7788 | SCOTT | 7566 | 20 |
7839 | KING | 10 | |
7844 | TURNER | 7698 | 30 |
7876 | ADAMS | 7788 | 20 |
7900 | JAMES | 7698 | 30 |
7902 | FORD | 7566 | 20 |
7934 | MILLER | 7782 | 10 |
阶层查询温习
■PRIOR
阶层查询的CONNECY BY condition的条件式需要用到PRIOR来指定父节点,
作为运算符,PRIOR和加(+)减(-)运算的优先级相同。 这个很重要,重点理解下:
prior empno= mgr
意思是:祖先(上一层记录)的empno等于本条记录的mgr,即:通过根节点遍历子节点
■阶层查询
语法:START WITH condition CONNECT BY NOCYCLE condition
START WITH 指定阶层的根
CONNECT BY 指定阶层的父/子关系
NOCYCLE 存在CONNECT BY LOOP的纪录时,也返回查询结果。
condition ... PRIOR expr = expr 或者 ... expr = PRIOR expr
■CONNECT BY子句的例子
通过CONNECT BY子句定义职员和上司的关系。
■LEVEL的例子
通过LEVEL虚拟列表示节点的关系。
从上级往下级够造树查询(默认排序):
这个公司的老大是KING,
7839 | KING | 10 |
因为他没有上级,按照EMPNO和MGR排下层级关系:
SQL>SELECT E.EMPNO, E.ENAME, E.MGR, E.DEPTNO, LEVEL
FROM EMP E
START WITH E.EMPNO = 7839
CONNECT BY PRIOR E.EMPNO = E.MGR;
EMPNO | ENAME | MGR | DEPTNO | LEVEL |
7839 | KING | 10 | 1 | |
7566 | JONES | 7839 | 20 | 2 |
7788 | SCOTT | 7566 | 20 | 3 |
7876 | ADAMS | 7788 | 20 | 4 |
7902 | FORD | 7566 | 20 | 3 |
7369 | SMITH | 7902 | 20 | 4 |
7698 | BLAKE | 7839 | 30 | 2 |
7499 | ALLEN | 7698 | 30 | 3 |
7521 | WARD | 7698 | 30 | 3 |
7654 | MARTIN | 7698 | 30 | 3 |
7844 | TURNER | 7698 | 30 | 3 |
7900 | JAMES | 7698 | 30 | 3 |
7782 | CLARK | 7839 | 10 | 2 |
7934 | MILLER | 7782 | 10 | 3 |
可以很清晰的看到层级关系,同时也可以看到结果按照DEPTNO和LEVEL的排序,看到部门的组成层级关系,如果我这样得到组织机构了,我还想按人名排序呢,因为默认的排序是按照EMPNO来进行的,此时:
■START WITH子句的排序
通过START WITH指定根节点,ORDER SIBLINGS BY保持阶层的顺序。
从上级往下级够造树查询(按组织的人名排序):
SQL>SELECT E.EMPNO, E.ENAME, E.MGR, E.DEPTNO, LEVEL
FROM EMP E
START WITH E.EMPNO = 7839
CONNECT BY PRIOR E.EMPNO = E.MGR
ORDER SIBLINGS BY E.ENAME;
EMPNO | ENAME | MGR | DEPTNO | LEVEL |
7839 | KING | 10 | 1 | |
7698 | BLAKE | 7839 | 30 | 2 |
7499 | ALLEN | 7698 | 30 | 3 |
7900 | JAMES | 7698 | 30 | 3 |
7654 | MARTIN | 7698 | 30 | 3 |
7844 | TURNER | 7698 | 30 | 3 |
7521 | WARD | 7698 | 30 | 3 |
7782 | CLARK | 7839 | 10 | 2 |
7934 | MILLER | 7782 | 10 | 3 |
7566 | JONES | 7839 | 20 | 2 |
7902 | FORD | 7566 | 20 | 3 |
7369 | SMITH | 7902 | 20 | 4 |
7788 | SCOTT | 7566 | 20 | 3 |
7876 | ADAMS | 7788 | 20 | 4 |
从下往上查询组织关系,例如我想知道
7369 | SMITH | 7902 | 20 | 4 |
SQL>SELECT E.EMPNO, E.ENAME, E.MGR, E.DEPTNO, LEVEL
FROM EMP E
START WITH E.EMPNO = 7369
CONNECT BY PRIOR E.MGR = E.EMPNO
ORDER SIBLINGS BY E.ENAME;
EMPNO | ENAME | MGR | DEPTNO | LEVEL |
7369 | SMITH | 7902 | 20 | 1 |
7902 | FORD | 7566 | 20 | 2 |
7566 | JONES | 7839 | 20 | 3 |
7839 | KING | 10 | 4 |
领导的个数和我差不多。。哈哈,还有一种情况,我们公司这种家族企业,虽然再人事组织关系上,领导关系鲜明,但是,例如SIMITH是最大领导KING的老婆,那么实际上的关系可能是这样的,SIMIT虽然听从FORD的工作安排命令,但是确可以直接安排老总KING,那么我将家族这种特殊的关系引入到组织机构里会怎样呢,请看:
先做下更新,将KING的领导MGR更新为SMITH的EMPNO:
UPDATE emp SET mgr = 7369 WHERE empno = 7839;
这个时候再去查询SMITH有多少个老大的时候就会无限制循环了,看看结果如何:
SQL>SELECT E.EMPNO, E.ENAME, E.MGR, E.DEPTNO, LEVEL
FROM EMP E
START WITH E.EMPNO = 7369
CONNECT BY PRIOR E.MGR = E.EMPNO
ORDER SIBLINGS BY E.ENAME
ORA-01436: CONNECT BY loop in user data
报错了原因是因为产生了CONNECT BY LOOP,这个时候怎么办呢,取组织关系的时候加上 NOCYCLE,试试就知道了:
SQL>SELECT E.EMPNO, E.ENAME, E.MGR, E.DEPTNO, LEVEL
FROM EMP E
START WITH E.EMPNO = 7369
CONNECT BY NOCYCLE PRIOR E.MGR = E.EMPNO
ORDER SIBLINGS BY E.ENAME;
得到了正确的结果,开来家族企业也得公私分开啊,不然只能停滞不前啊。
例如我们想看二把手JONES在公司的地位,关键看他领导了几个部门,最重要的是什么部门。例如财务部是生杀大权的诞生地,采购部是油水回流地,查查看:
SQL>
SELECT ENAME "Employee",
CONNECT_BY_ISCYCLE "Cycle",
EMPNO,
MGR,
LEVEL,
SYS_CONNECT_BY_PATH(ENAME, '/') "Path"
FROM EMP
WHERE LEVEL <= 5
AND DEPTNO = 20
START WITH ENAME = 'JONES'
CONNECT BY NOCYCLE PRIOR EMPNO = MGR
AND LEVEL <= 5;
Employee | Cycle | EMPNO | MGR | LEVEL | Path |
JONES | 0 | 7566 | 7839 | 1 | /JONES |
SCOTT | 0 | 7788 | 7566 | 2 | /JONES/SCOTT |
ADAMS | 0 | 7876 | 7788 | 3 | /JONES/SCOTT/ADAMS |
FORD | 0 | 7902 | 7566 | 2 | /JONES/FORD |
SMITH | 0 | 7369 | 7902 | 3 | /JONES/FORD/SMITH |
底下一共有4名员工,员工的领导关系一目了然。
如果我想知道这个公司每个部门每个月要发多少工资,首先明确10部门是KING所在的部门,这个部门相当于管理部门,负责管理底下所有的部门,这个时候怎么办?好的,看看下面的:
SQL>SELECT NAME, SUM(SAL) AS SAL
FROM (SELECT CONNECT_BY_ROOT ENAME AS NAME, ENAME, LEVEL, SAL
FROM EMP
WHERE DEPTNO = 10
CONNECT BY NOCYCLE PRIOR EMPNO = MGR)
GROUP BY NAME;
NAME SAL
MILLER 1300
CLARK 3750
KING 8750
OK,温习完毕,再来解答帖子里的这个问题
http://topic.csdn.net/u/20110928/11/1306858a-ba5d-4d71-b7c2-984bc3fd20f7.html
大致转换到SCOTT表里的需求为:查2把手的工资总和 或者说给定条件,查询下一层级的工资总和
这里是老总KING要给他的直接下属总共发多少工资?如下SQL:
SQL>SELECT EMPNO, SUM(SAL) AS TOTAL_SAL
FROM (SELECT CONNECT_BY_ROOT E.EMPNO AS EMPNO,
E.ENAME,
E.SAL,
LEVEL AS ILEVEL
FROM EMP E
WHERE LEVEL = 2
START WITH E.EMPNO = 7839
CONNECT BY PRIOR E.EMPNO = E.MGR)
GROUP BY EMPNO;
EMPNO TOTAL_SAL
7839 8275
或许应该再算下奖金,或者是年终奖,不过想想没有必要,这么拼命的做项目,数量再大也不会过超过4位数,花了几个小时学习下不足的知识点。。。以慰藉内心!