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> --但是有特例对分页分页问题我们一定要对子查询进行排序; 这里我们先暂时记一下这个我们还没学到;