四.Oracle聚合函数和内外全连接
1.聚合函数
同时对一组数据行进行操作,对每组行返回一行输出结果,叫做分组函数。(将多行数据分成一行或多行,每组行只返回一行结果)
1.1聚合函数不能出现在where字句中
1.2常用的聚合函数:
count: 表示返回满足条件的总行数,(注:建议用rowid统计总行数,因为它代表唯一的物理地址,或者用唯一标识符(主键);)
使用 * 效率慢,因为它先会去select * from all_tab_cols(字典表)去搜索表有那些列,然后再去分析那个列查询速度更快
例:select count(rowid) from emp;统计emp表的总行数
sum :表示求和
例:select sum(sal+nvl(comm,0)) from emp; 表示求出薪水加奖金的总和,此处用到了nvl();
avg :表示求平均数
例:select avg(sal) from emp; 表示求出平均薪水。
max :表示求最大值
例:select max(sal) from emp; 表示求出最高薪水。
min : 表示求最小值
例:select min(sal) from emp; 表示求出最低薪水。
2.Order by
Order by :表示对查询语句进行排序
例:select job from emp order by job; 表示按工作职位进行排序,默认为升序。
select job from emp order by job desc; 表示按工作职位进行降序
如果查询中包含一个聚合函数,而所选择的列不在聚合函数中,那么这些列就必须出现在GROUP BY子句中.(不用聚合函数的列必须出现在group by后)
例1 :select ename,sex from emp group by sex;(错,ename没有用聚合函数,也没有出现在group by后面,因为将sex分成两组,但ename有很多,到底输出那个ename呢?)
例2: select max(ename),sex from emp group by sex;(对)
3.Having:字句过滤组
注意:HAVING子句必须出现在GROUP BY语句中.group by 后的任何语句(包括排序..)都是分完组后才进行结果运算
例:SELECT deptno,AVG(sal) FROM emp GROUP BY deptno HAVING AVG(sal) > 2000 表示查出月薪大于2000的部门编号及平均月薪。
4.聚合函数的嵌套:
聚合函数可以嵌套使用,但这条语句必须是GROUP BY语句.且SELECT子句就只能有这个嵌套聚合函数.(如下例子不能有deptno)
例:1:求出部门平均月薪的最高值.
select deptno,max(avg(sal)) from emp group by deptno(错,首先分组成部门求出各部门的平均月薪,再求出部门最高值,部门有多个,最高值只有一个)
select max(avg(sal)) from emp group by deptno(对)
例2:求出部门平均月薪最高的部门编号和平均月薪(子查询)
select deptno,avg(sal) from emp group by deptno having avg(sal)=(
select max(avg(sal)) from emp group by deptno
)
5.笛卡尔积:将左边的一条语句按顺序和右边表的每一条数据依次做交集,最终的结果就是左边的总条数 * 右边的总条数
例:select * from emp,dept;
笛卡尔积过滤(将两张表总相同的列进行条件判断)
例:列出dept表中的deptno 等于 emp表中的deptno的所用数据行
select * from dept d,emp e where d.deptno = e.deptno --86语法
select * from emp e inner join dept d on e.deptno = d,deptno --92语法
笛卡尔积的用处:实现多表连接,用于多表查询。
内连接:
如果作为主表的表的某一条记录和右表的任意一条记录都无法匹配 不会保留这条表的记录(必须是条件成立才出结果)
例:(e.deptno=d.deptno符合这个条件才保留,不符合不保留)
外连接:
外连接又分为 左外连接 和 右外连接
左外连接(left): 以左表为主表 如果在右表匹配不到任何记录 会保留主表的记录
例:(select * from emp e left join dept d on e.deptno=d.deptno符合这个条件保留,不符合条件的emp(主表)表记录也会保留)
右外连接(right):以右表为主表 如果在左表匹配不到任何记录 会保留主表的记录
例:(select * from emp e right join dept d on e.deptno=d.deptno符合这个条件保留,不符合条件的dept(主表)表记录也会保留)
全连接:
全连接(full)就是将左右外联的结果取并集
例:select * from emp e full join dept d on e.deptno=d.deptno(符合条件保留,emp,dept两个表不符合条件的也全部保留)
交叉连接:cross join
语法:SELECT … FROM join_table CROSS JOIN join_table2;
没有ON子句和WHERE子句,它返回所有连接表中所有数据行的笛卡尔积。
其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
示例:SELECT * FROM emp CROSS JOIN dept;
6.学习练习题:
现有一分组对抗赛表(team),表中有队名和组编号(type): 中国 A 韩国 A 日本 A 美国 B 巴西 B 荷兰 B现要通过查询实现A组和B组进行循环对抗,写出SELECT语句(交叉连接) select * from(select * from team where type='A')cross join(select * from team where type='B'); 查询出员工姓名及其所在的部门名 SELECT ename,dname FROM emp e INNER JOIN dept d ON e.deptno=d.deptno 查询出月薪大于2000的员工姓名、月薪、受雇日期及其所在的部门名,输出结果按受雇日期排序 SELECT ename,sal,hiredate,dname FROM emp INNER JOIN dept ON emp.deptno=dept.deptno WHERE emp.sal>2000 ORDER BY hiredate; 查询出每个员工的姓名、月薪以及月薪等级 select ename,sal,grade from emp e INNER JOIN salgrade s on sal between s.loal and s.hisal; 查询出每个员工的姓名、职位、月薪、部门名称、部门位置、以及月薪的等级,结果按员工编号排序。 select ename,job,sal,dname,loc,grade from emp e INNER JOIN dept d ON e.depto=d.deptno INNER JOIN salgrade s ON e.sal between s.losal and s.hisal; 查询出所有的部门编号、部门名及该部门下的所有员工的姓名 SELECT dept.deptno,dname,ename FROM dept LEFT JOIN emp ON dept.deptno=emp.deptno; 查询出每个员工的编号、姓名、职位及它的领导的姓名及职位 自连接:参与连接的表都是同一张表。(通过给表取别名虚拟出) SELECT e.empno,e.ename,e.job,m.ename,m.job FROM emp e LEFT JOIN emp m ON e.mgr=m.empno;
以下主要为dept 表和 emp表的练习
--聚合函数 select * from emp --count()次数里面最好是rowid唯一快,*不建议使用,全部太慢 select count(rowid) from emp --求出员工总人数。 select count(rowid)from emp --求出公司每月要支付的月薪总数。 select sum(sal)from emp --求出最高月薪、最低月薪。 select max(sal),min(sal) from emp --求出公司的平均月薪。 select avg(sal) from emp --group by语句练习 select max(sal),job from emp group by job --如果查询中包含一个聚合函数,而所选择的列不在聚合函数中,那么这些列就必须出现在GROUP BY子句中。(也就是说不用聚合函数的列必须出现在group by后面) select empno,count(rowid) from emp group by empno select count(rowid) from emp group by job select job,sex,count(rowid) from emp group by job,sex select sum(sal+comm) from emp--任何数字与空值进行计算都为空,这里不为空是因为组函数会忽略空值 select empno,max(ename) from emp group by empno select sum(sal+nvl(comm,0)) from emp select sum(sal)from emp select max(avg(sal)) from emp group by deptno --显示每个部门的员工数量。 select deptno,count(rowid) from emp group by deptno --显示每种职位的名及平均月薪。 select job,avg(sal)from emp group by job --显示每年入职的员工数量及年份。 select to_char(hiredate,'yyyy'),count(rowid)from emp group by to_char(hiredate,'yyyy') --显示部门平均月薪大于2000的部门编号及平均月薪。(?) select deptno,avg(sal)from emp group by deptno having avg(sal)>2000 --查询出不是总裁(PRESIDENT)的职位名以及该职位的员工月薪总和,还要满足同职位的员工的月薪总和大于4500。输出结果按月薪的总和降序排列。 select job,sum(sal) from emp where job!='PRESIDENT' group by job having sum(sal)>4500 order by sum(sal) desc --聚合函数嵌套 --求出部门平均月薪的最高值。(嵌套) select max(avg(sal)) from emp group by deptno --思考:求出部门平均月薪最高的部门编号和平均月薪(子查询) select deptno,avg(sal) from emp group by deptno having avg(sal)=( select max(avg(sal))from emp group by deptno ) select * from emp; select * from dept; select * from salgrade; --笛卡尔积 select * from dept d,emp e where d.deptno=e.deptno and d.dname='研发部'; select * from emp e,dept d where e.deptno=d.deptno --86语法 --内联:(如果作为主表的表的某一条记录和右表的任意一条记录都无法匹配,不会保留主表的记录)(必须是条件成立才出现结果) select * from emp e inner join dept d on e.deptno=d.deptno --92语法 --左外联(如果作为主表的表的某一条记录和右表的任意一条记录都无法匹配,会保留主表的记录) select * from emp e left join dept d on e.deptno=d.deptno --右外联(right) select * from emp e right join dept d on e.deptno=d.deptno --全连接 就是将左右外联的结果取并集full select * from emp e full join dept d on e.deptno=d.deptno --查询出员工姓名及其所在的部门名 select e.ename,d.dname from emp e inner join dept d on e.deptno=d.deptno --查询出月薪大于2000的员工姓名,月薪,受雇日期及其所在的部门名,输出结果接受雇日期排序 select e.ename,e.sal,e.hiredate,d.dname from emp e inner join dept d on e.deptno=d.deptno where e.sal>2000 order by e.hiredate asc --查询出每个员工的姓名,月薪以及月薪等级 select e.ename,e.sal,s.grade from emp e inner join salgrade s on e.sal between s.losal and s.hisal --查询出每个员工的姓名,职位,月薪,部门名称,部门位置,以及月薪的等级,结果按员工编号排序 select e.ename,e.job,e.sal,d.dname,d.loc,s.grade from emp e inner join dept d on e.deptno=d.deptno inner join salgrade s on e.sal between s.losal and s.hisal order by e.deptno asc --查询出所有的部门编号、部门名及该部门下的所有员工的姓名。 select d.dname,e.ename from dept d left join emp e on d.deptno=e.deptno select d.deptno,d.dname,e.ename from dept d inner join emp e on d.deptno=e.deptno --查询出每个员工的编号、姓名、职位及它的领导的姓名及职位。 select e.ename,e.empno,e.job,d.ename,d.job from emp e inner join emp d on e.mgr=d.empno; select e.ename,d.ename from emp e inner join emp d on e.mgr=d.empno; --查询出每个员工的姓名、职位、月薪、所属部门名、月薪等级及其领导的姓名、职位、所属部门名、月薪等级。