• Oracle学习笔记(八)


    十一、子查询
    1、子查询概述
    学习子查询的原因
    事例:查询工资比SCOTT高的员工信息
    思路:1、scott的工资
    select sal from emp where ename='SCOTT';
    2、比3000高的员工信息
    select * from emp where sal>3000;
    子查询方式:
    select * from emp where sal> (select sal from emp where ename='SCOTT');

    2、子查询的使用
    子查询注意的10个问题
    (a)子查询语法中的小括号

    (b)子查询的书写风格
    格式:
    select *
    from emp
    where sal> (select sal
    from emp
    where ename='SCOTT');
    (c)可以使用子查询的位置:where,select,having,from
    select事例
    单行子查询,只返回一条记录
    事例:
    select empno,ename,sal,(select job from emp where empno=7830) 第四列 from emp;

    多行子查询,返回多条记录

    having事例:
    10号部门的平均工资:
    select deptno,avg(sal) from emp group by deptno having avg(sal)>(select max(sal) from emp where deptno=30);

    from事例:
    select * from(select empno,ename,sal from emp);

    (d)不可以使用子查询的位置:group by
    不允许的情况:
    select avg(sal) from emp group by (select deptno from emp);
    (e)强调:from后面的子查询
    (1)查询员工信息:员工号,姓名,月薪
    select * from (select empno as 员工号,ename as 姓名,sal as 月薪 from emp);
    (2)查询员工信息:员工号,姓名,月薪,年薪
    select * from (select empno as 员工号,ename as 姓名,sal as 月薪,sal*12 as 年薪 from emp);

    (f)主查询和子查询可以不是同一张表
    事例:
    查询部门名称是SALES的员工信息
    select * from emp where deptno=(select deptno from dept where dname='SALES');

    select e.* from emp e,dept d where e.deptno=d.deptno and d.dname='SALES';
    (g)一般不在子查询中,使用排序,但在Top-N分析问题中,必须对子查询排序
    事例:
    找到员工表中工资最高的前三名,如下格式:
    ROWNUM EMPNO ENAME SAL
    1 7839 KING 5000
    2 7788 SCOTT 3000
    3 7902 FORD 3000
    ---------rownum 行号 伪劣
    select rownum,empno,ename,sal from emp where rownum<=3 order by sal desc;

    行号需要注意的两个问题:
    行号永远按照默认的顺序生成
    行号只能使用<,<=;不能使用>,>=

    (h)一般先执行子查询,再执行主查询,但相关子查询例外
    事例:
    找到员工表中薪水大于本部门平均薪水的员工
    select empno,ename,sal,(select avg(nvl(sal,0)) from emp where deptno=e.deptno) as 平均薪水
    from emp e
    where sal>(select avg(nvl(sal,0)) from emp where deptno=e.deptno);
    3、子查询的类型
    (i)单行子查询只能使用单行操作符,多行子查询只能使用多行操作符
    单行操作符
    操作符 含义
    = equal to
    > greater than
    >= greater than or equal to
    < less than
    <= less than or equal to
    <> Not equal to

    多行操作符
    操作符 含义
    IN 等于列表中的任何一个
    ANY 和子查询返回的任意一个值比较
    ALL 和子查询返回的所有值比较

    单行子查询:
    事例:
    查询员工信息,要求:
    A、职位与7566员工一样
    B、薪水大于7782员工的薪水
    select * from emp where job =(select job from emp where empno=7566) and sal >(select sal from emp where empno=7782);
    注意:单行子查询只能使用单行操作符
    事例:
    查询工资最低的员工信息
    select * from emp where sal=(select min(sal) from emp);
    事例:
    查询最低工资大于20号部门最低工资的部门号和部门的最低工资
    select deptno,min(sal) from emp group by deptno having min(sal)>(select min(sal) from emp where deptno=20);

    多行子查询:
    多行操作符:in
    事例:
    查询部门名称是SALES和ACCOUNTING的员工信息
    select * from emp where deptno in (select deptno from dept where dname='SALES' or dname='ACCOUNTING');

    select e.* from emp e, dept d where e.deptno=d.deptno and (d.dname='SALES' or dname='ACCOUNTING');

    多行操作符:any
    事例:
    查询工资比30号部门任意一个员工高的员工信息
    select * from emp where sal > any(select sal from emp where deptno=30);
    select * from emp where sal > (select min(sal) from emp where deptno=30);

    多行操作符:all
    事例:
    查询工资比30号部门所有员工高的员工信息
    select * from emp where sal > all(select sal from emp where deptno=30);
    select * from emp where sal > (select max(sal) from emp where deptno=30);

    (j)注意:子查询中有null问题
    单行:
    子查询不返回任何行(错误的例子)
    select ename,job from emp where job (select job from emp where ename='Tom');
    事例:
    查询不是老板的员工(错误)
    select * from emp where empno not in (select mgr from emp);
    正确
    select * from emp where empno not in (select mgr from emp where mgr is not null);
    4、综合事例
    目标:
    (1)灵活运用select语句解决实际的问题
    (2)通过四个具体的示例,演示如何编写高效的查询语句
    示例一:
    分页查询显示员工信息:显示员工号,姓名,月薪
    要求:(1)每页显示四条记录
    (2)显示第二页的员工
    (3)按照月薪降序排列
    注意:rownum只能使用<,<=,不能使用>,>=
    Oracle 通过拼接子查询方式实现分页操作
    select r,empno,ename,sal
    from (select rownum r,empno,ename,sal
    from (select rownum,empno,ename,sal from emp order by sal desc) e1
    where rownum<=8) e2
    where r>=5;
    查看伪列的行号
    select rownum,r,empno,ename,sal
    from (select rownum r,empno,ename,sal
    from (select rownum,empno,ename,sal from emp order by sal desc) e1
    where rownum<=8) e2
    where r>=5;

    示例二:
    找到员工表中薪水大于本部门平均薪水的员工.
    方法一:
    select empno,ename,sal,(select avg(sal) from emp where deptno=e.deptno) as 平均薪水
    from emp e
    where sal>(select avg(sal) from emp where deptno=e.deptno);
    方法二:
    select e.empno,e.ename,e.sal, d.avgsal as 平均薪水
    from emp e,(select deptno ,avg(sal) avgsal from emp group by deptno) d
    where e.deptno=d.deptno and e.sal>d.avgsal;

    执行计划设置:
    explain plan for
    select empno,ename,sal,(select avg(sal) from emp where deptno=e.deptno) as 平均薪水
    from emp e
    where sal>(select avg(sal) from emp where deptno=e.deptno);
    查看执行计划:
    select * from table(dbms_xplan.display);

    执行计划设置:
    explain plan for
    select e.empno,e.ename,e.sal, d.avgsal as 平均薪水
    from emp e,(select deptno ,avg(sal) avgsal from emp group by deptno) d
    where e.deptno=d.deptno and e.sal>d.avgsal;
    查看执行计划:
    select * from table(dbms_xplan.display);

    结论:相关子查询更加的快捷

    示例三:
    按部门统计员工人数,按照如下格式输出:
    Total 1980 1981 1982 1987
    ======== ======= ========== ======== =========
    14 1 10 1 2

    注意:员工的入职年份已知

    方法一(函数方式):
    select count(*) Total,
    sum(decode(to_char(hiredate,'YYYY'),'1980',1,0)) "1980",
    sum(decode(to_char(hiredate,'YYYY'),'1981',1,0)) "1981",
    sum(decode(to_char(hiredate,'YYYY'),'1982',1,0)) "1982",
    sum(decode(to_char(hiredate,'YYYY'),'1987',1,0)) "1987"
    from emp;

    方法二(子查询方式):
    select
    (select count(*) from emp) Total,
    (select count(*) from emp where to_char(hiredate,'yyyy')='1980') "1980",
    (select count(*) from emp where to_char(hiredate,'yyyy')='1981') "1981",
    (select count(*) from emp where to_char(hiredate,'yyyy')='1982') "1982",
    (select count(*) from emp where to_char(hiredate,'yyyy')='1987') "1987"
    from dual;

    示例四:
    ============选课表===============
    create table pm_ci(
    CI_ID varchar2(20) not null,
    STU_IDS varchar2(100)
    );
    insert into pm_ci values('1','1,2,3,4');
    insert into pm_ci values('2','1,4');

    ==========学生表========
    create table pm_stu(
    STU_ID varchar2(20) not null,
    STU_NAME varchar2(20)
    );
    insert into pm_stu values('1','张三');
    insert into pm_stu values('2','李四');
    insert into pm_stu values('3','王五');
    insert into pm_stu values('4','赵六');

    要求查询以下结果:
    CI_ID STU_NAME
    ==================== ===================
    1 张三,李四,王五,赵六
    2 张三,赵六

    提示:
    1、需要进行两个表的连接查询,为两个表都取别名
    2、使用instr(a,b)函数,该函数的含义为:如果字符串b在字符串a的里面,则返回的是b在a中的位置,即返回值大于0.
    3、需要用到分组查询
    4、使用wm_concat(cols)函数对学生姓名用逗号进行拼接.

    解法:
    select ci_id,wm_concat(stu_name) stu_name from (select ci_id,stu_name from pm_ci c,pm_stu s where instr(c.stu_ids,s.stu_id)>0) t group by ci_id;

  • 相关阅读:
    团队项目成员和题目
    最大联通子数组
    站立会议5
    关于jsp之间href传参(中文)乱码问题
    站立会议4
    典型用户和用户场景描述
    站立会议3
    站立会议2
    站立会议1
    第七周学习进度情况
  • 原文地址:https://www.cnblogs.com/liuyangfirst/p/6418537.html
Copyright © 2020-2023  润新知