ORACLE_高级查询(1)_组函数_分组查询_子查询_Unit_3;

Topic 1 : 组函数

SQL> --组函数操作多行返回一行,又称多行函数;
SQL> -- count(*) 求总行数
SQL> select count(*) from emp;

  COUNT(*)
----------
        14

SQL> --也可以查找单独的一列有多少行
SQL> --因为select后面跟的就是列数
SQL> select count(empno) from emp;

COUNT(EMPNO)
------------
          14

SQL> --count 是查找有多少行的  他不会去重 但是我们i可以手动的去重 (distinct)
SQL> select count(distinct sal) from emp;

COUNT(DISTINCTSAL)
------------------
                12

SQL> --我们介绍过常量  这里我们查询的时候也可以查询常量
SQL> select count('helloWorld') from emp;

COUNT('HELLOWORLD')
-------------------
                 14

SQL> --道理是一样的
SQL> --但是这里我们就要考虑效率的问题  在这里我们写常量是效率是最高的  所以我们在查询的时候呢  我们就可以
SQL> --通过常量来查询;
SQL> -- 例题 : 查询emp中不同工作一共有多少种
SQL> select count(distinct job) from emp;

COUNT(DISTINCTJOB)
------------------
                 5

SQL> --sum() avg() min() max()  他们四个的用法是一样 只不过是含义不同
SQL> select sum(sal) "总工资", avg(sal) "平均工资", min(sal) "最小工资", max(sal) "最大工资" from emp;

    总工资   平均工资   最小工资   最大工资
---------- ---------- ---------- ----------
     29025 2073.21429        800       5000

SQL> --对与我们查询日期的最大值和最小值我们也是跟日常生活的逻辑是一样的  最大的日期肯定是最近发生的
SQL> select max(hiredate) 最近入职的 min(hiredate) 最早入职的 from emp;
select max(hiredate) 最近入职的 min(hiredate) 最早入职的 from emp
                                     *
第 1 行出现错误:
ORA-00923: 未找到要求的 FROM 关键字


SQL> select max(hiredate) 最近入职的,min(hiredate) 最早入职的 from emp;

最近入职的     最早入职的
-------------- --------------
23-5月 -87     17-12月-80

SQL> -- 重点:组函数会自动过滤掉null  所以你在使用组函数运算的时候在也不用担心null(max)最大和sum(null参与的运算结果都为空)
SQL> --count() 肯定也会把null的数据过滤掉;
SQL> -- 组函数包括: count sum min max

 

 

Topic 2 : 分组:

SQL> --分组
SQL> --group by
SQL> -- 例一: 求各个部门的平均工资:
SQL> select avg(sal) from emp group by deptno;

  AVG(SAL)
----------
1566.66667
      2175
2916.66667

SQL> select deptno,avg(sal) from emp group by deptno;

    DEPTNO   AVG(SAL)
---------- ----------
        30 1566.66667
        20       2175
        10 2916.66667


SQL> --上面这个查询语句我们在平均工资前面添加了deptno这一个列之所以可以添加是因为我们分组的时候是按照他进行分组的  我们只能添 加group by 后面有的东西;
SQL> --  分组查询的时候没在组函数的列必须在group by的后面  要不然就不能在查询列之中;
SQL> --  我们在没有进行分组查询之前对于select查询出来的列  我们可以用where进行行的筛选
SQL> --  但是分组之后就不行了  我们只能使用having来筛选  如下:
SQL> select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;

    DEPTNO   AVG(SAL)
---------- ----------
        20       2175
        10 2916.66667

SQL> -- 这是因为不能在where中使用组函数但是可以在having中使用组函数(多行函数);
SQL> -- 我们在学排序的时候能会出现第一个排序相同的  我们就可以根据第二个条件进行排序
SQL> -- 我们的分组也是这个样子的
SQL> -- 先按照部门进行分组  再按照工作进行分组
SQL> select deptno,job,avg(sal) from emp group by deptno,job;

    DEPTNO JOB                  AVG(SAL)
---------- ------------------ ----------
        20 CLERK                     950
        30 SALESMAN                 1400
        20 MANAGER                  2975
        30 CLERK                     950
        10 PRESIDENT                5000
        30 MANAGER                  2850
        10 CLERK                    1300
        10 MANAGER                  2450
        20 ANALYST                  3000

已选择9行。

SQL> -- 其实就是不同部门的不同工作的平均工资;
SQL> -- 对于分组的问题  我们要先想自己要根据什么进行分组  确定以后我们再看参照物;
SQL> -- 最后加上我们要查询的那个
SQL>
SQL>
SQL>
SQL>
SQL> --  增强的group by
SQL> -- 我们先用两种函数都写一个问题  来对比记忆:
SQL> select deptno,job,sum(sal) from emp group by deptno,job;

    DEPTNO JOB                  SUM(SAL)
---------- ------------------ ----------
        20 CLERK                    1900
        30 SALESMAN                 5600
        20 MANAGER                  2975
        30 CLERK                     950
        10 PRESIDENT                5000
        30 MANAGER                  2850
        10 CLERK                    1300
        10 MANAGER                  2450
        20 ANALYST                  6000

已选择9行。

SQL> --  因为他是乱序的我们加一个排序  整理一下
SQL> select deptno,job,sum(sal) from emp group by deptno,job order by deptno;

    DEPTNO JOB                  SUM(SAL)
---------- ------------------ ----------
        10 CLERK                    1300
        10 MANAGER                  2450
        10 PRESIDENT                5000
        20 ANALYST                  6000
        20 CLERK                    1900
        20 MANAGER                  2975
        30 CLERK                     950
        30 MANAGER                  2850
        30 SALESMAN                 5600

已选择9行。

SQL> select deptno,job,sum(sal) from emp group by rollup(deptno,job) order by deptno;

    DEPTNO JOB                  SUM(SAL)
---------- ------------------ ----------
        10 CLERK                    1300
        10 MANAGER                  2450
        10 PRESIDENT                5000
        10                          8750
        20 ANALYST                  6000
        20 CLERK                    1900
        20 MANAGER                  2975
        20                         10875
        30 CLERK                     950
        30 MANAGER                  2850
        30 SALESMAN                 5600

    DEPTNO JOB                  SUM(SAL)
---------- ------------------ ----------
        30                          9400
                                   29025

已选择13行。

SQL> set pagesize=30;
SP2-0268: pagesize 选项的编号无效
SQL> set pagesize 30;
SQL> select deptno,job,sum(sal) from emp group by rollup(deptno,job) order by deptno;

    DEPTNO JOB                  SUM(SAL)
---------- ------------------ ----------
        10 CLERK                    1300
        10 MANAGER                  2450
        10 PRESIDENT                5000
        10                          8750
        20 ANALYST                  6000
        20 CLERK                    1900
        20 MANAGER                  2975
        20                         10875
        30 CLERK                     950
        30 MANAGER                  2850
        30 SALESMAN                 5600
        30                          9400
                                   29025

已选择13行。

SQL> break on deptno;
SQL> select deptno,job,sum(sal) from emp group by rollup(deptno,job) order by deptno;

    DEPTNO JOB                  SUM(SAL)
---------- ------------------ ----------
        10 CLERK                    1300
           MANAGER                  2450
           PRESIDENT                5000
                                    8750
        20 ANALYST                  6000
           CLERK                    1900
           MANAGER                  2975
                                   10875
        30 CLERK                     950
           MANAGER                  2850
           SALESMAN                 5600
                                    9400
                                   29025

已选择13行。

SQL> --这个报表形式就做出来了  要是我们不想根据deptno来打断点了  那么我们就写break on null;
SQL> break on null;
SQL> select deptno,job,sum(sal) from emp group by rollup(deptno,job) order by deptno;

    DEPTNO JOB                  SUM(SAL)
---------- ------------------ ----------
        10 CLERK                    1300
        10 MANAGER                  2450
        10 PRESIDENT                5000
        10                          8750
        20 ANALYST                  6000
        20 CLERK                    1900
        20 MANAGER                  2975
        20                         10875
        30 CLERK                     950
        30 MANAGER                  2850
        30 SALESMAN                 5600
        30                          9400
                                   29025

已选择13行。

SQL> --又回到了原来的样子  我们也要注意一下rollup();的用法  就是根据哪两个进行分组  然后进行每一组的求和;

Topic 3 : 子查询 :

SQL> --子查询
SQL> --查询工资比scott高的员工信息
SQL> -- 没有子查询的话我们就要先查询  scott的sal  然后查询比3000高的员工
SQL> select sal from emp where ename='SCOTT';
  2  select sal from emp where ename='SCOTT';
select sal from emp where ename='SCOTT';
                                       *
第 1 行出现错误:
ORA-00911: 无效字符


SQL> select sal from emp where ename='SCOTT';

       SAL
----------
      3000

SQL> select * from emp where sal>3000;

     EMPNO ENAME                JOB                       MGR HIREDATE
---------- -------------------- ------------------ ---------- --------------
       SAL       COMM     DEPTNO
---------- ---------- ----------
      7839 KING                 PRESIDENT                     17-11月-81
      5000                    10


SQL> set linesize 160;
SQL> set linesize 160;\
SP2-0268: linesize 选项的编号无效
SQL> select * from emp where sal>3000;

     EMPNO ENAME                JOB                       MGR HIREDATE              SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------
      7839 KING                 PRESIDENT                     17-11月-81           5000                 10

SQL> --我们用子查询来实现这个题目;
SQL> select * from emp where sal>(select sal from emp where ename='SCOTT');

     EMPNO ENAME                JOB                       MGR HIREDATE              SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------
      7839 KING                 PRESIDENT                     17-11月-81           5000                 10

SQL> -- 子查询的查询结果作为主查询的查询条件
SQL> --子查询可以出现的位置where select having from 但是不能出现group by后面的信息;
SQL> select ename,(select job from emp where empno=7839) 第二列 from emp;

ENAME                第二列
-------------------- ------------------
SMITH                PRESIDENT
ALLEN                PRESIDENT
WARD                 PRESIDENT
JONES                PRESIDENT
MARTIN               PRESIDENT
BLAKE                PRESIDENT
CLARK                PRESIDENT
SCOTT                PRESIDENT
KING                 PRESIDENT
TURNER               PRESIDENT
ADAMS                PRESIDENT

ENAME                第二列
-------------------- ------------------
JAMES                PRESIDENT
FORD                 PRESIDENT
MILLER               PRESIDENT

已选择14行。

SQL> --我们select的后面只能跟列和常量  这里我们利用子查询查询下出来一个常量  就如上图所示;
SQL> --  组的筛选用having
SQL> -- 题目: 查询最低工资比20号部门最低工资高的编号及工资;
SQL> -- 上面的查询的工资是最低工资   查询一个部门里面的最低工资  肯定要按照部门分组的 然后对工资进行筛选;
SQL> select * from emp where sal>(select sal from emp where ename="SCOTT");
select * from emp where sal>(select sal from emp where ename="SCOTT")
                                                             *
第 1 行出现错误:
ORA-00904: "SCOTT": 标识符无效


SQL> select * from emp where sal>(select sal from emp where ename='SCOTT');

     EMPNO ENAME                JOB                       MGR HIREDATE              SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------
      7839 KING                 PRESIDENT                     17-11月-81           5000                 10

SQL> --注意我们的这一句 ename='SCOTT'必须要用单引号;
SQL> --日期字符串要用单引号而设置列名的时候用双引号
SQL> select * from emp where sal>(select sal from emp where ename='scott');

未选定行

SQL> --关键字的大小写不敏感但是列名这写表中的数据是大小写敏感的;
SQL> --查询最低工资比部门编号为20号的最低工资还低的部门编号和最低工资;
SQL> seleect deptno,min(sal)from emp
SP2-0734: 未知的命令开头 "seleect de..." - 忽略了剩余的行。
SQL> select deptno,min(sal)from emp
  2  group by deptno
  3  having min(sal)>(select min(sal) from epm where deptno=20);
having min(sal)>(select min(sal) from epm where deptno=20)
                                      *
第 3 行出现错误:
ORA-00942: 表或视图不存在


SQL> select deptno,min(sal)from emp
  2  group by deptno
  3  having min(sal)>(select min(sal) from emp where deptno=20);

    DEPTNO   MIN(SAL)
---------- ----------
        30        950
        10       1300

SQL> --from后面使用子查询(可以对原表进行一些增删改)
SQL> select * from (select empno,ename,sal,sal*12 from emp) t;

     EMPNO ENAME                       SAL     SAL*12
---------- -------------------- ---------- ----------
      7369 SMITH                       800       9600
      7499 ALLEN                      1600      19200
      7521 WARD                       1250      15000
      7566 JONES                      2975      35700
      7654 MARTIN                     1250      15000
      7698 BLAKE                      2850      34200
      7782 CLARK                      2450      29400
      7788 SCOTT                      3000      36000
      7839 KING                       5000      60000
      7844 TURNER                     1500      18000
      7876 ADAMS                      1100      13200

     EMPNO ENAME                       SAL     SAL*12
---------- -------------------- ---------- ----------
      7900 JAMES                       950      11400
      7902 FORD                       3000      36000
      7934 MILLER                     1300      15600

已选择14行。

SQL> set pagesize 200;
SQL> select * from (select empno,ename,sal,sal*12 from emp) t;

     EMPNO ENAME                       SAL     SAL*12
---------- -------------------- ---------- ----------
      7369 SMITH                       800       9600
      7499 ALLEN                      1600      19200
      7521 WARD                       1250      15000
      7566 JONES                      2975      35700
      7654 MARTIN                     1250      15000
      7698 BLAKE                      2850      34200
      7782 CLARK                      2450      29400
      7788 SCOTT                      3000      36000
      7839 KING                       5000      60000
      7844 TURNER                     1500      18000
      7876 ADAMS                      1100      13200
      7900 JAMES                       950      11400
      7902 FORD                       3000      36000
      7934 MILLER                     1300      15600

已选择14行。

SQL> --这里是把这些列重命名为t表了  查询t表的全部内容
SQL> --例题:根据员工表和部门表查询sales部门员工的信息
SQL> --解析:我们先根据部门表查出sales部门的部门标号  然后根据部门编号在员工表中查员工的信息
SQL> select * from emp where deptno=(select deptno from dept where dname='SALES');

     EMPNO ENAME                JOB                       MGR HIREDATE              SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------
      7499 ALLEN                SALESMAN                 7698 20-2月 -81           1600        300      30
      7521 WARD                 SALESMAN                 7698 22-2月 -81           1250        500      30
      7654 MARTIN               SALESMAN                 7698 28-9月 -81           1250       1400      30
      7698 BLAKE                MANAGER                  7839 01-5月 -81           2850                 30
      7844 TURNER               SALESMAN                 7698 08-9月 -81           1500          0      30
      7900 JAMES                CLERK                    7698 03-12月-81            950                 30

已选择6行。

SQL> --通过不同的表实现子查询
SQL> --子查询可以使用单行操作符(=,<)也可以使用多行操作符(in,like)
SQL> ed
已写入 file afiedt.buf

  1* select * from emp where deptno in (select deptno from dept where dname='SALES' or dname='RESEARCH')
SQL> /

     EMPNO ENAME                JOB                       MGR HIREDATE              SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------
      7566 JONES                MANAGER                  7839 02-4月 -81           2975                 20
      7902 FORD                 ANALYST                  7566 03-12月-81           3000                 20
      7876 ADAMS                CLERK                    7788 23-5月 -87           1100                 20
      7369 SMITH                CLERK                    7902 17-12月-80            800                 20
      7788 SCOTT                ANALYST                  7566 19-4月 -87           3000                 20
      7521 WARD                 SALESMAN                 7698 22-2月 -81           1250        500      30
      7844 TURNER               SALESMAN                 7698 08-9月 -81           1500          0      30
      7499 ALLEN                SALESMAN                 7698 20-2月 -81           1600        300      30
      7900 JAMES                CLERK                    7698 03-12月-81            950                 30
      7698 BLAKE                MANAGER                  7839 01-5月 -81           2850                 30
      7654 MARTIN               SALESMAN                 7698 28-9月 -81           1250       1400      30

已选择11行。

SQL> --我们在第一问的基础上又添加了一个部门  所以我们主查询就要用 in了
SQL> --子查询的运算符:any和all  字面理解他们的意思就行  第一个只要有一个满足就行  第二个是都要满足
SQL> --查询工资比30号部门其中一个员工工资高的员工信息(就是比30号中最低工资高就行)
SQL> select * from emp where sal >
  2  any (select sal from emp where deptno=30);

     EMPNO ENAME                JOB                       MGR HIREDATE              SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------
      7839 KING                 PRESIDENT                     17-11月-81           5000                 10
      7902 FORD                 ANALYST                  7566 03-12月-81           3000                 20
      7788 SCOTT                ANALYST                  7566 19-4月 -87           3000                 20
      7566 JONES                MANAGER                  7839 02-4月 -81           2975                 20
      7698 BLAKE                MANAGER                  7839 01-5月 -81           2850                 30
      7782 CLARK                MANAGER                  7839 09-6月 -81           2450                 10
      7499 ALLEN                SALESMAN                 7698 20-2月 -81           1600        300      30
      7844 TURNER               SALESMAN                 7698 08-9月 -81           1500          0      30
      7934 MILLER               CLERK                    7782 23-1月 -82           1300                 10
      7521 WARD                 SALESMAN                 7698 22-2月 -81           1250        500      30
      7654 MARTIN               SALESMAN                 7698 28-9月 -81           1250       1400      30
      7876 ADAMS                CLERK                    7788 23-5月 -87           1100                 20

已选择12行。

SQL> --查询工资比30号部门所有员工工资都高的员工信息
SQL> select * from emp where sal >
  2  all (select sal from emp where deptno=30);

     EMPNO ENAME                JOB                       MGR HIREDATE              SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------
      7566 JONES                MANAGER                  7839 02-4月 -81           2975                 20
      7788 SCOTT                ANALYST                  7566 19-4月 -87           3000                 20
      7902 FORD                 ANALYST                  7566 03-12月-81           3000                 20
      7839 KING                 PRESIDENT                     17-11月-81           5000                 10

SQL> --all可以用max等价  any可以用min等价;
SQL> --例题:查询普通员工的信息
SQL> --解析:emp中每一个员工后面都会有MGR这一列  这一列代表每一行员工对应的经理的编号  所以我们可以查询 员工编号不在MGR
SQL> --中的就说明他不是经理
SQL> select * from emp where empno not in
  2  (select MGR from emp);

未选定行

SQL> --上面出现未选定行的原因就是not in 不能与空连用  要是与空连用就必然会出现未选定行 但是可以与in连用;
SQL> --所以我们把MGR为空的那个给排除掉就好了(为空的原因嘛就是他已经是最大的领导了  所以没有人领导他)
SQL> select * from emp where empno not in
  2  (select MGR from emp where MGR is not null);

     EMPNO ENAME                JOB                       MGR HIREDATE              SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- -------------- ---------- ---------- ----------
      7369 SMITH                CLERK                    7902 17-12月-80            800                 20
      7499 ALLEN                SALESMAN                 7698 20-2月 -81           1600        300      30
      7521 WARD                 SALESMAN                 7698 22-2月 -81           1250        500      30
      7654 MARTIN               SALESMAN                 7698 28-9月 -81           1250       1400      30
      7844 TURNER               SALESMAN                 7698 08-9月 -81           1500          0      30
      7876 ADAMS                CLERK                    7788 23-5月 -87           1100                 20
      7900 JAMES                CLERK                    7698 03-12月-81            950                 30
      7934 MILLER               CLERK                    7782 23-1月 -82           1300                 10

已选择8行。

SQL> --子查询是不需要排序的  因为他排不排序对主查询都是无关的;
SQL> --但是有特例对分页分页问题我们一定要对子查询进行排序;  这里我们先暂时记一下这个我们还没学到;

猜你喜欢

转载自blog.csdn.net/qq_38053395/article/details/82839818