zoukankan      html  css  js  c++  java
  • Oracle笔记(八) 复杂查询及总结

    一、复杂查询

    1、 列出至少有一个员工的所有部门编号、名称,并统计出这些部门的平均工资、最低工资、最高工资。

    1、确定所需要的数据表:

    • emp表:可以查询出员工的数量;
    • dept表:部门名称;
    • emp表:统计信息;

    2、确定已知的关联字段:

    • emp.deptno=dept.deptno;  

    第一步:找出至少有一个员工的部门编号

    SELECT deptno,COUNT(empno)
    FROM emp
    GROUP BY deptno
    HAVING COUNT(empno)>1;

    第二步:找到部门名称,肯定使用部门表,因为现在的数据量较小,所以可以将之前的emp表和dept表两个进行连接,统一采用多字段分组的方式查询;

    SELECT d.deptno,d.dname,COUNT(e.empno)
    FROM emp e,dept d
    WHERE e.deptno=d.deptno(+)
    GROUP BY d.deptno,d.dname
    HAVING COUNT(e.empno)>1;

    第三步:依然需要继续统计

    SELECT d.deptno,d.dname,COUNT(e.empno),AVG(sal),MIN(sal),MAX(sal)
    FROM emp e,dept d
    WHERE e.deptno=d.deptno(+)
    GROUP BY d.deptno,d.dname
    HAVING COUNT(e.empno)>1;

    2、 列出薪金比“SMITH”或“ALLEN”多的所有员工的编号、姓名、部门名称、其领导姓名。

    1、确定所需要的数据表:

    • emp表:查询出“SMITH”或“ALLEN”工资;
    • emp表:最终的显示需要编号、姓名;
    • emp表:领导的姓名,自身关联;
    • dept表:部门名称;

    2、确定已知的关联字段:

    • 雇员和领导:emp.mgr=memp.empno;
    • 雇员和部门:emp.deptno=dept.deptno;

    第一步:找出“SMITH”或“ALLEN”的工资

    SELECT sal FROM emp WHERE ename IN('SMITH','ALLEN');

    第二步:以上的查询返回的多行单列的记录,按照子查询的要求在WHERE子句中写合适,所以这个时候将上面的查询作为一个子查询出现,继续查询符合此要求的员工的编号、姓名。

    SELECT e.empno,e.ename
    FROM emp e
    WHERE e.sal>ALL(
        SELECT sal
        FROM emp
        WHERE ename IN('SMITH','ALLEN'));

    第三步:查询出部门的名称,引入部门表,同时增加消除笛卡尔积的条件

    SELECT e.empno,e.ename,d.dname
    FROM emp e,dept d
    WHERE e.sal>ALL(
        SELECT sal
        FROM emp
        WHERE ename IN('SMITH','ALLEN'))
        AND e.deptno=d.deptno;

    第四步:领导的信息需要emp表自身关联

    SELECT e.empno,e.ename,d.dname,m.ename
    FROM emp e,dept d,emp m
    WHERE e.sal>ALL(
        SELECT sal
        FROM emp
        WHERE ename IN('SMITH','ALLEN'))
        AND e.deptno=d.deptno
        AND e.mgr=m.empno(+);

    3、 列出所有员工的编号、姓名及其直接上级的编号、姓名,显示的结果按领导年工资的降序排列。

    1、确定所需要的数据表:

    • emp表:员工的编号、姓名;
    • emp表:领导的编号、姓名、计算年薪;

    2、确定已知的关联字段:emp.mgr=memp.empno;

    SELECT e.empno,e.ename,m.empno,m.ename,(m.sal+NVL(m.comm,0))*12 income
    FROM emp e,emp m
    WHERE e.mgr=m.empno(+)
    ORDER BY income DESC;

    4、列出受雇日期早于其直接上级的所有员工的编号、姓名、部门名称、部门位置、部门人数。

    1、确定所需要的数据表:

    • emp表:雇员的编号、姓名;
    • emp表:求出领导的工作日期;
    • dept表:部门名称、位置;
    • emp表:统计部门人数;

    2、确定已知的关联字段:

    • 雇员和部门:emp.deptno=dept.deptno;
    • 雇员和领导:emp.mgr=memp.empno;

    第一步:列出受雇日期早于其直接上级的所有员工的编号、姓名 —— 自身关联emp表。

    SELECT e.empno,e.ename
    FROM emp e,emp m
    WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate;

    第二步:加入部门信息,继续引入部门表

    SELECT e.empno,e.ename,d.dname,d.loc
    FROM emp e,emp m,dept d
    WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate
    AND e.deptno=d.deptno;

    额外提问,此时的笛卡尔积:emp表的14条 * emp表的14条 * dept表的4条;

    第三步:统计部门人数,此时由于要使用统计函数,而且以上的查询也无法再直接出现统计函数,所以使用子查询完成

    SELECT e.empno,e.ename,d.dname,d.loc,temp.count
    FROM emp e,emp m,dept d,(
        SELECT deptno dno,COUNT(empno) count
        FROM emp
        GROUP BY deptno) temp
    WHERE e.mgr=m.empno(+) AND e.hiredate<m.hiredate
        AND e.deptno=d.deptno
        AND e.deptno=temp.dno;

    当查询显示的时候需要统计信息,但是又不能直接使用统计函数查询的话,通过子查询在FROM子句之后进行统计。

    5、列出部门名称和这些部门的员工信息(数量、平均工资),同时列出那些没有员工的部门。

    1、确定所需要的数据表:

    • dept表:部门的信息;
    • emp表:求出所有的统计信息;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal)
    FROM emp e,dept d
    WHERE e.deptno(+)=d.deptno
    GROUP BY d.deptno,d.dname,d.loc;

    6、列出所有“CLERK”(办事员)的姓名及其部门名称,部门的人数,工资等级。

    1、确定所需要的数据表:

    • emp表:找到办事员的姓名;
    • dept表:部门名称;
    • emp表:统计求出部门的人数;
    • salgrade表:查询工资等级;

    2、确定已知的关联字段:

    • emp表和dept表:emp.deptno=dept.deptno;
    • emp表和salgrade表:emp.sal BETWEEN salgrade.losal AND salgrade.hisal;

    第一步:找到所有办事员的姓名

    SELECT e.ename
    FROM emp e
    WHERE job='CLERK';

    第二步:找到部门信息,引入dept表,同时增加消除笛卡尔积的条件

    SELECT e.ename,d.dname
    FROM emp e,dept d
    WHERE job='CLERK' AND e.deptno=d.deptno;

    第三步:部门人数需要额外的统计,但是本程序的查询里面已经不可能继续使用COUNT()函数,所以写子查询统计

    SELECT e.ename,d.dname,temp.count
    FROM emp e,dept d,(
        SELECT deptno dno,COUNT(empno) count
        FROM emp
        GROUP BY deptno) temp
    WHERE e.job='CLERK' AND e.deptno=d.deptno
        AND d.deptno=temp.dno;

    第四步:雇员的工资等级,继续引入salgrade表

    SELECT e.ename,d.dname,temp.count,s.grade
    FROM emp e,dept d,(
        SELECT deptno dno,COUNT(empno) count
        FROM emp
        GROUP BY deptno) temp,salgrade s
    WHERE e.job='CLERK' AND e.deptno=d.deptno
        AND d.deptno=temp.dno
        AND e.sal BETWEEN s.losal AND s.hisal;

    7、列出最低薪金大于1500的各种工作及从事此工作的全部雇员人数及所在部门名称、位置、平均工资。

    1、确定所需要的数据表:

    • emp表:最低薪金大于1500的工作肯定需要使用emp表统计求出,以及可以求出雇员人数;
    • dept表:求出些雇员所在的部门信息;
    • emp表:统计求出部门的平均工资;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    第一步:使用emp表按照job分组,统计最低工资(HAVING)和人数

    SELECT e.job,COUNT(e.empno)
    FROM emp e
    GROUP BY e.job
    HAVING MIN(e.sal)>1500;

    第二步:要查询出雇员所在的部门信息,但是以上的查询能跟dept表有关联吗?

    以上的查询和dept表之间并没有关联字段,那么如果没有关联字段,一定会有笛卡尔积产生,但是多表查询必须要消除笛卡尔积,所以必须联系;

    • 以上的查询可以和emp表的job字段关联;
    • 要引入的dept表也可以和emp表的deptno字段关联;
    SELECT temp.job,temp.count,d.dname,e.ename
    FROM dept d,(
        SELECT e.job job,COUNT(e.empno) count
        FROM emp e
        GROUP BY e.job
        HAVING MIN(e.sal)>1500) temp,
        emp e
    WHERE e.deptno=d.deptno AND e.job=temp.job;

    第三步:求出一个部门的平均工资,使用emp表在子查询中统计

    SELECT temp.job,temp.count,d.dname,e.ename,res.avg
    FROM dept d,(
        SELECT e.job job,COUNT(e.empno) count
        FROM emp e
        GROUP BY e.job
        HAVING MIN(e.sal)>1500) temp,
        emp e,(
        SELECT deptno dno,AVG(sal) avg
        FROM emp
        GROUP BY deptno) res
    WHERE e.deptno=d.deptno AND e.job=temp.job
        AND e.deptno=res.dno;

    本题目之所以出的如此之复杂,目的是训练大家寻找关联字段的能力,但是本题目没有任何的意义,知道就行了。

    8、列出在部门“SALES”(销售部)工作的员工姓名、基本工资、雇佣日期、部门名称、假定不知道销售部的部门编号。

    1、确定所需要的数据表:

    • emp表:员工姓名、基本工资、雇佣日期;
    • dept表:找到销售部的部门编号、部门名称;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    SELECT e.ename,e.sal,e.hiredate,d.dname
    FROM emp e,dept d
    WHERE e.deptno=d.deptno
    AND d.dname='SALES';

    9、列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,公司的工资等级。

    1、确定所需要的数据表:

    • emp表:可以求出公司的平均薪金;
    • emp表:员工的信息;
    • dept表:部门的信息;
    • emp表:领导的信息;
    • salgrade表:工资等级;

    2、确定已知的关联字段:

    • 雇员和部门:emp.deptno=dept.deptno;
    • 雇员和领导:emp.mgr=memp.empno;
    • 雇员和工资等级:emp.sal BETWEEN salgrade.losal AND salgrade.hisal;

    第一步:求出公司的平均薪金

    SELECT AVG(sal) FROM emp;

    第二步:将以上的子查询放在WHERE子句之中,作为一个查询条件,求出满足此条件的雇员信息。

    SELECT e.empno,e.ename,e.job,e.sal
    FROM emp e
    WHERE e.sal>(
        SELECT AVG(sal) FROM emp);

    第三步:找到部门的名称

    SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc
    FROM emp e,dept d
    WHERE e.sal>(
        SELECT AVG(sal) FROM emp)
        AND e.deptno=d.deptno;

    第四步:找到领导的信息

    SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc,m.ename
    FROM emp e,dept d,emp m
    WHERE e.sal>(
        SELECT AVG(sal) FROM emp)
        AND e.deptno=d.deptno
        AND e.mgr=m.empno(+);

    第五步:找到工资等级

    SELECT e.empno,e.ename,e.job,e.sal,d.dname,d.loc,m.ename,s.grade
    FROM emp e,dept d,emp m,salgrade s
    WHERE e.sal>(
        SELECT AVG(sal) FROM emp)
        AND e.deptno=d.deptno
        AND e.mgr=m.empno(+)
        AND e.sal BETWEEN s.losal AND s.hisal;

    10、列出与“SCOTT”从事相同工作的所有员工及部门名称,部门人数。

    1、确定所需要的数据表:

    • emp表:找到SCOTT的工作;
    • emp表:员工的信息;
    • dept表:部门名称;
    • emp表:部门人数;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    第一步:找到SCOTT的工作

    SELECT job FROM emp WHERE ename='SCOTT';

    第二步:以上的子查询返回单行单列的数据,所以可以在WHERE子句中出现,以这个条件查找满足要求的雇员信息

    SELECT e.empno,e.ename,e.job
    FROM emp e
    WHERE e.job=(
        SELECT job
        FROM emp
        WHERE ename='SCOTT')
        AND e.ename<>'SCOTT';

    第三步:找到部门名称

    SELECT e.empno,e.ename,e.job,d.dname
    FROM emp e,dept d
    WHERE e.job=(
        SELECT job
        FROM emp
        WHERE ename='SCOTT')
        AND e.ename<>'SCOTT'
        AND e.deptno=d.deptno;

    第四步:找到部门人数,需要统计,所以在FROM子句之中编写

    SELECT e.empno,e.ename,e.job,d.dname,temp.count
    FROM emp e,dept d,(
        SELECT deptno dno,COUNT(empno) count
        FROM emp
        GROUP BY deptno) temp
    WHERE e.job=(
        SELECT job
        FROM emp
        WHERE ename='SCOTT')
        AND e.ename<>'SCOTT'
        AND e.deptno=d.deptno
        AND temp.dno=e.deptno;

    11、列出公司各个工资等级雇员的数量、平均工资。

    1、确定所需要的数据表:

    • emp表:统计出数据;
    • salgrade表:得出工资等级;

    2、确定已知的关联字段:emp.sal BETWEEN salgrade.losal AND s.hisal;

    本程序实际上就是一个多字段分组而已,唯一不同的是,将分组条件设置为salgrade表中的字段;

    SELECT s.grade,s.losal,s.hisal,COUNT(e.empno),AVG(e.sal)
    FROM emp e,salgrade s
    WHERE e.sal BETWEEN s.losal AND s.hisal
    GROUP BY s.grade,s.losal,s.hisal;

    12、列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金、部门名称。

    1、确定所需要的数据表:

    • emp表:找出所有在30部门工作的雇员的工资;
    • emp表:最终显示的雇员姓名;
    • dept表:找到部门名称;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    第一步:找到30部门工作的雇员的工资

    SELECT sal FROM emp WHERE deptno=30;

    第二步:高于30部门,使用ALL操作符,引入emp表,查询姓名和薪金

    SELECT e.empno,e.ename
    FROM emp e
    WHERE sal>ALL(
        SELECT sal FROM emp WHERE deptno=30)
        AND e.deptno=d.deptno;

    13、列出在每个部门工作的员工数量、平均工资和平均服务期限。

    1、确定所需要的数据表:

    • dept表:找到部门信息;
    • emp表:统计出数量、平均工资、平均服务年限;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    直接将dept和emp表关联,使用多字段分组即可,但是对于服务年限需要一个计算过程。

    SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal),AVG(MONTHS_BWTWEEN(SYSDATE,e.hiredate)/12) year
    FROM emp e,dept d
    WHERE e.deptno(+)=d.deptno
    GROUP BY d.deptno,d.dname,d.loc;

    14、列出所有员工的姓名、部门名称和工资。

    1、确定所需要的数据表:

    • emp表:找到员工姓名;
    • dept表:部门名称;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    SELECT e.ename,d.dname,e.sal
    FROM emp e,dept d
    WHERE e.deptno=d.deptno;

    15、列出所有部门的详细信息和部门人数。

    1、确定所需要的数据表:

    • emp表:统计信息;
    • dept表:查询部门信息;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    SELECT d.deptno,d.dname,d.loc,COUNT(e.empno)
    FROM emp e,dept d
    WHERE e.deptno(+)=d.deptno
    GROUP BY d.deptno,d.dname,d.loc;

    16、列出各种工作的最低工资及从事此工作的雇员姓名。

    1、确定所需要的数据表:

    • emp表:统计出各个工作的最低工资;
    • emp表:查找出雇员姓名;

    第一步:按照职位统计各个职位的最低工资

    SELECT job,MIN(sal) FROM emp
    GROUP BY job;

    第二步:将以上的查询和emp表关联

    SELECT e.ename,e.job,e.sal
    FROM emp e,(
        SELECT job,MIN(sal) FROM emp
        GROUP BY job) temp
    WHERE e.job=temp.job AND e.sal=temp.min;

    17、列出各个部门的MANAGER(经理)的最低薪金、姓名、部门名称、部门人数。

    1、确定所需要的数据表:

    • emp表:找到经理的薪金、姓名;
    • dept表:部门名称;
    • emp表:统计部门人数;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    第一步:找到所有部门的经理

    SELECT deptno,MIN(sal)
    FROM emp
    WHERE job='MANAGER'
    GROUP BY deptno;

    第二步:找到姓名,但是以上的子查询,不能再出现其他的字段

    SELECT e.ename,e.sal
    FROM emp e,(
        SELECT deptno dno,MIN(sal) sal
        FROM emp
        WHERE job=’MANAGER’
        GROUP BY deptno) temp
    WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job='MANAGER';

    第三步:加入部门的名称信息

    SELECT e.ename,e.sal,d.dname
    FROM emp e,(
        SELECT deptno dno,MIN(sal) sal
        FROM emp
        WHERE job='MANAGER'
        GROUP BY deptno) temp,dept d
    WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job='MANAGER'
        AND e.deptno=d.deptno;

    第四步:统计部门人数

    SELECT e.ename,e.sal,d.dname,res.count
    FROM emp e,(
        SELECT deptno dno,MIN(sal) sal
        FROM emp
        WHERE job=’MANAGER’
        GROUP BY deptno) temp,dept d,(
        SELECT deptno dno,COUNT(empno) count
        FROM emp
        GROUP BY deptno) res
    WHERE e.deptno=temp.dno AND e.sal=temp.sal AND e.job='MANAGER'
        AND e.deptno=d.deptno AND res.dno=d.deptno;

    18、列出所有员工的年工资,所在部门名称,按年薪从低到高排序。

    1、确定所需要的数据表:

    • emp表:统计年工资;
    • dept表:部门名称;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    SELECT e.ename,e.sal*12 income,d.dname
    FROM emp e,dept d
    WHERE e.deptno=d.deptno
    ORDER BY income;

    19、查出某个员工的上级主管及所在部门名称,并要求出这些主管中的薪水超过3000。

    1、确定所需要的数据表:

    • emp表:员工的信息;
    • emp表:领导的信息;
    • dept表:部门名称;

    2、确定已知的关联字段:

    • 雇员和部门:emp.deptno=dept.deptno;
    • 雇员和领导:emp.mgr=memp.empno;
    SELECT DISTINCT m.ename,d.dname,m.sal
    FROM emp e,emp m,dept d
    WHERE e.mgr=m.empno AND m.deptno=d.deptno AND m.sal>3000;

    20、求出部门名称中,带‘S’字符的部门员工的工资合计、部门人数。

    1、确定所需要的数据表:

    • emp表:进行统计信息;
    • dept表:部门名称;

    2、确定已知的关联字段:emp.deptno=dept.deptno;

    SELECT d.dname,SUM(e.sal),COUNT(e.empno)
    FROM emp e,dept d
    WHERE e.deptno(+)=d.deptno AND d.dname LIKE%S%GROUP BY d.dname;

    21、给任职日期超过30年或者在87年雇佣的雇员加薪,加薪原则:10部门增长10%,20部门增长20%,30部门增长30%,依次类推。

    UPDATE emp SET
        sal=(1 + deptno/100)*sal
    WHERE MONTHS_BETWEEN(SYSDATE,hiredate)/12>30
        OR TO_CHAR(hiredate,’yyyy’)=1987;

    以上的所有题目作为DML操作的总结,这些题目结果都不重要,关键是解决问题的思路,这些只能通过代码的不断练习。

    二、总结

    1、 多表查询:在进行查询语句编写的时候,一定要确定所需要关联的数据表,而且只要是表的关联查询,就一定会存在笛卡尔积的问题,使用关联字段消除此问题。

    在使用多表查询的时候要考虑到左右连接的问题,Oracle之外的数据库可以使用SQL:1999语法控制左右连接;

    2、 所有的统计函数是用于进行数据统计操作的,而统计要在分组中进行(或者是单独使用),分组使用GROUP BY子句,是在某一列上存在重复数据的时候才会使用分组操作,而分组后的过滤使用HAVING子句完成,所有的分组函数可以嵌套,但是嵌套之后的分组函数之中不能再有其他的查询字段,包括分组字段;

    3、 子查询:结合限定查询、多表查询、分组统计查询完成各个复杂查询的操作,子查询一般在WHERE和FROM之后出现较多;

    4、 数据库的更新操作一定要受到事务的控制,事务的两个命令:COMMIT、ROLLBACK,每一个连接到数据库上的用户都使用一个SESSION表示;

    5、 数据表的分页查询显示依靠ROWNUM伪列,以后在开发之中必定100%要使用。

  • 相关阅读:
    hihoCoder #1176 : 欧拉路·一 (简单)
    228 Summary Ranges 汇总区间
    227 Basic Calculator II 基本计算器II
    226 Invert Binary Tree 翻转二叉树
    225 Implement Stack using Queues 队列实现栈
    224 Basic Calculator 基本计算器
    223 Rectangle Area 矩形面积
    222 Count Complete Tree Nodes 完全二叉树的节点个数
    221 Maximal Square 最大正方形
    220 Contains Duplicate III 存在重复 III
  • 原文地址:https://www.cnblogs.com/mchina/p/2653417.html
Copyright © 2011-2022 走看看