多表查询
select * from BONUS;
select * from DEPT;
select * from EMP;
select * from SALGRADE;
BONUS表 |
ENAME |
JOB |
SAL |
COMM |
DEPT表 |
DEPTNO |
DNAME |
LOC |
1 |
10 |
ACCOUNTING |
NEW YORK |
2 |
20 |
RESEARCH |
DALLAS |
3 |
30 |
SALES |
CHICAGO |
4 |
40 |
OPERATIONS |
BOSTON |
EMP表 |
EMPNO |
ENAME |
JOB |
MGR |
HIREDATE |
SAL |
COMM |
DEPTNO |
1 |
7369 |
SMITH |
CLERK |
7902 |
1980/12/17 |
800.00 |
|
20 |
2 |
7499 |
ALLEN |
SALESMAN |
7698 |
1981/2/20 |
1600.00 |
300.00 |
30 |
3 |
7521 |
WARD |
SALESMAN |
7698 |
1981/2/22 |
1250.00 |
500.00 |
30 |
4 |
7566 |
JONES |
MANAGER |
7839 |
1981/4/2 |
2975.00 |
|
20 |
5 |
7654 |
MARTIN |
SALESMAN |
7698 |
1981/9/28 |
1250.00 |
1400.00 |
30 |
6 |
7698 |
BLAKE |
MANAGER |
7839 |
1981/5/1 |
2850.00 |
|
30 |
7 |
7782 |
CLARK |
MANAGER |
7839 |
1981/6/9 |
2450.00 |
|
10 |
8 |
7788 |
SCOTT |
ANALYST |
7566 |
1987/4/19 |
3000.00 |
|
20 |
9 |
7839 |
KING |
PRESIDENT |
|
1981/11/17 |
5000.00 |
|
10 |
10 |
7844 |
TURNER |
SALESMAN |
7698 |
1981/9/8 |
1500.00 |
0.00 |
30 |
11 |
7876 |
ADAMS |
CLERK |
7788 |
1987/5/23 |
1100.00 |
|
20 |
12 |
7900 |
JAMES |
CLERK |
7698 |
1981/12/3 |
950.00 |
|
30 |
SALGRADE表 |
GRADE |
LOSAL |
HISAL |
1 |
1 |
700 |
1200 |
2 |
2 |
1201 |
1400 |
3 |
3 |
1401 |
2000 |
4 |
4 |
2001 |
3000 |
5 |
5 |
3001 |
9999 |
xlsx格式转换为html格式: http://pressbin.com/tools/excel_to_html_table/index.html
一:笛卡尔积
/*
多表查询:笛卡尔积
select * from 表1,表2
*/
select * from emp,dept; --56条数据中有没有意义的结果,所以需要加条件筛选有意义的结果
select * from emp,dept where emp.DEPTNO =DEPT.DEPTNO;
select * from emp e1 ,dept d1 where e1.DEPTNO =d1.DEPTNO; --别名,简化sql语句
二:内联接
/*
内联接:
隐式内联接:
等值内联接: where e1.DEPTNO =d1.DEPTNO
不等值内联接:where e1.DEPTNO <> d1.DEPTNO 无意义,不用
自联接:
显示内联接:
select * from 表1 inner join 表2 on 连接条件
inner 关键字可以省略
*/
select *from emp;
select EMPNO || \'员工编号\',ENAME || \'员工姓名\',JOB || \'职业\',MGR || \'经理编号\',HIREDATE ||\'雇佣日期\',SAL,COMM,DEPTNO ||\'部门编号\' from emp; --可以查出所有信息
--查询员工编号,员工姓名,经理的编号,经理的姓名 :通过上面可以发现所有的信息都在emp表中
select * from emp e1,emp m1 where e1.mgr = m1.empno ;
select e1.empno,e1.ename,m1.mgr,m1.ename from emp e1,emp m1 where e1.mgr = m1.empno ;
--查询员工编号,员工姓名,员工的部门名称,经理的编号,经理的姓名
select * from dept; --查询一下部门表
select e1.empno,e1.ename,d1.dname,m1.mgr,m1.ename
from emp e1,emp m1,dept d1
where e1.mgr = m1.empno
and e1.deptno=d1.deptno; --注意and联接
--查询员工编号,员工姓名,员工的部门名称,经理的编号,经理的姓名,经理的部门
select e1.empno,e1.ename,d1.dname,m1.mgr,m1.ename ,d2.dname
from emp e1,emp m1,dept d1,dept d2
where e1.mgr = m1.empno
and e1.deptno=d1.deptno
and m1.deptno=d2.deptno;
--总结:员工的部门:员工表与部门表,经理的部门:经理表与部分表
--查询员工编号,员工姓名,员工的工资等级,员工的部门名称,经理的编号,经理的姓名,经理的部门
select * from SALGRADE;
select e1.empno,e1.ename,s1.grade,d1.dname,m1.mgr,m1.ename ,d2.dname
from emp e1,emp m1,dept d1,dept d2 ,SALGRADE s1
where e1.mgr = m1.empno
and e1.deptno=d1.deptno
and m1.deptno=d2.deptno
and e1.sal between s1.losal and s1.hisal;
--给工资等级取中文名 1对应一级,2对应二级,,,
select * from SALGRADE;
select e1.empno,e1.ename,
d1.dname,m1.mgr,m1.ename ,d2.dname,
case s1.grade
when 1 then \'一级\'
when 2 then \'二级\'
when 3 then \'三级\'
when 4 then \'四级\'
else
\'五级\'
end "等级"
from emp e1,emp m1,dept d1,dept d2 ,SALGRADE s1
where e1.mgr = m1.empno
and e1.deptno=d1.deptno
and m1.deptno=d2.deptno
and e1.sal between s1.losal and s1.hisal; --建议把工资等级放最后
-- end 后面取别名
--查询员工部门和员工部分所在的位置
select * from emp e1,dept d1 where e1.DEPTNO=d1.deptno; --先查出所有字段
select e1.ename,d1.loc
from emp e1,dept d1
where e1.DEPTNO=d1.deptno;
--显示内联接:
--查询员工部门和员工部分所在的位置
select * from emp e1 inner join dept d1 on e1.deptno=d1.deptno;
select e1.ename,d1.loc from emp e1 inner join dept d1 on e1.deptno=d1.deptno;
/*
外连接:
左外连接:left outer joinL:左表中所有数据,如果右表中没有对应记录,就显示为空
右外连接:right ouoter join:右表中所有数据,如果左表中没有对应记录,就显示为空
outer关键字可以省略
oracle中的外连接:(+):如果没有对应的值就加上空值
select * from emp e1 inner join dept d1 on e1.deptno=d1.deptno; --内连接
select * from emp e1,dept d1 where e1.deptno=d1.deptno(+); --类似于左外连接
select * from emp e1,dept d1 where e1.deptno(+)=d1.deptno; --类似于右外连接
*/
--左外连接
select * from emp;
select * from dept ;
select * from emp e1 left outer join dept d1 on e1.deptno=d1.deptno; --注意别少了join和on关键字
三:子查询
/*
子查询:查询语句中嵌套查询语句
*/
1:查询最高工资的员工信息
--查询出最高工资
select max(sal) from emp;
--工资等于最高工资的员工信息
select * from emp where sal = (select max(sal) from emp);
--查询比雇员7654工资高,同时和7788从事相同工作的员工信息
--1:雇员7654的工资
select sal from emp where EMPNO=7654; --1250.00
--2:7788相同工作
select job from emp where EMPNO=7788; --ANALYST
--3:同时and
select * from emp where sal > (select sal from emp where EMPNO=7654) and job = (select job from emp where EMPNO=7788);
--查询每个部门最低工资的员工信息和他所在的部门信息 --重点
--1:查询每个部门最低工资--group by分组统计
select DEPTNO,min(sal) minsal from emp group by DEPTNO; --当成t1表
--2:员工工资等于他所处部门的最低工资
select * from emp e1,t1 where e1.deptno = t1.deptno and e1.sal = t1.minsal;
select *
from emp e1,(select DEPTNO,min(sal) minsal from emp group by DEPTNO) t1
where e1.deptno = t1.deptno and e1.sal = t1.minsal;
--3:查询部门相关信息
select *
from emp e1,(select DEPTNO,min(sal) minsal from emp group by DEPTNO) t1 ,
dept d1
where e1.deptno = t1.deptno and e1.sal = t1.minsal
and e1.deptno=d1.deptno;
四:条件查询
/*
in
not in
any
all
*/
1:查询所有领导的信息
--查询所有经理的编号
select mgr from emp; --有空值
select distinct mgr from emp; --去重
--结果 --员工编号在经理编号中就是经理
select * from emp e1 where e1.empno in (select mgr from emp);
2:查询不是领导的信息
select * from emp e1 where e1.empno not in (select mgr from emp); --因为有空值,所以无输出,空值问题
select * from emp e1 where e1.empno not in (select mgr from emp where mgr is not null); --正确
--exists(查询语句):数据量非常大的时候,非常高效.当查询语句有结果,返回true,否则返回false
--查询有员工的部门信息
select * from emp;
select * from dept;
select * from dept d1 where exists(select * from emp e1 where e1.deptno = d1.deptno);
五:rownum
--找到员工表中工资最高的前三名
select * from emp order by sal desc ; --不正确,没有提取前3列
/*
rownum:伪列,用来表示行号,是oracle中特有的,默认值是1,在查询出结果之后再添加1。
rownum不做大于号判断,可以做小于号判断
mysql使用limit关键字
*/
select rownum,e1.* from emp e1; --注意查看rownum列
--查询rownum大于2的所有记录
select rownum,e1.* from emp e1 where rownum >2 ; --没有任何记录,rownum从1开始,查询一条,当前rownum为1,小于2,没有记录
--查询rownum大于等于1的所有记录
select rownum,e1.* from emp e1 where rownum >=1 ; --所有记录
--查询rownum小于6的所有记录
select rownum,e1.* from emp e1 where rownum <6 ;
--rownum排序会打乱
--SQL的执行顺序:from, where, group by, having, select [rownum],order by
--找到员工表中工资最高的前三名
select * from emp order by sal desc ; 可以把它当成一张表,重新查询,重新生成新的rownum
select rownum,t1.* from (select * from emp order by sal desc ) t1;
select rownum,t1.* from (select * from emp order by sal desc ) t1 where rownum <= 3; --最终结果
--找到员工表中薪水大于本部门平均薪水的员工
--1:找到所有部门的平均薪水
select DEPTNO,floor(avg(SAL)) FROM emp group by DEPTNO; --把它的结果当成新表他t1
--2:员工工资 >本部门平均工资
select * FROM emp e1,(select DEPTNO, floor(avg(SAL)) avgsal FROM emp group by DEPTNO) t1 where e1.deptno =t1.DEPTNO and e1.sal > t1.avgsal;
--方法二:关联子查询
SELECT * FROM emp e WHERE e.sal > (SELECT avg(sal) FROM emp e2 group by deptno having e.deptno =e2.deptno)
--统计每年入职的员工个数
--只统计年
select hiredate from emp;
select to_char(hiredate,\'yyyy\') from emp;
--分组统计
select to_char(hiredate,\'yyyy\') from emp group by to_char(hiredate,\'yyyy\') ;
select to_char(hiredate,\'yyyy\'),count(1) from emp group by to_char(hiredate,\'yyyy\') ; --最终结果
--结果横竖倒立
|1987|1980|
| 2| 3 |
select to_char(hiredate,\'yyyy\') yy ,count(1) cc from emp group by to_char(hiredate,\'yyyy\') ;
--1.1
select
case yy when \'1987\' then 2 end xx
FROM (select to_char(hiredate,\'yyyy\') yy ,count(1) cc from emp group by to_char(hiredate,\'yyyy\')) ;
--1.2 :end别名需要用双引号,单引号报错
select
case yy when \'1987\' then 2 end "1987"
FROM (select to_char(hiredate,\'yyyy\') yy ,count(1) cc from emp group by to_char(hiredate,\'yyyy\')) ;
--1.3使用聚合函数sum,去除行记录的null值
select
sum (case yy when \'1987\' then cc end) "1987"
FROM (select to_char(hiredate,\'yyyy\') yy ,count(1) cc from emp group by to_char(hiredate,\'yyyy\')) ;
--1.4 统计其它,举一反三
select
sum (case yy when \'1987\' then cc end) "1987",
sum (case yy when \'1980\' then cc end) "1980"
FROM (select to_char(hiredate,\'yyyy\') yy ,count(1) cc from emp group by to_char(hiredate,\'yyyy\')) ;
--统计员工总数
select
sum(cc) "总数"
FROM (select to_char(hiredate,\'yyyy\') yy ,count(1) cc from emp group by to_char(hiredate,\'yyyy\')) ;
--把每天员工入职个数和员工总数汇合在一起
select
sum (case yy when \'1987\' then cc end) "1987",
sum (case yy when \'1980\' then cc end) "1980",
sum (case yy when \'1982\' then cc end) "1982",
sum (case yy when \'1981\' then cc end) "1981",
sum(cc) "总数"
FROM (select to_char(hiredate,\'yyyy\') yy ,count(1) cc from emp group by to_char(hiredate,\'yyyy\')) ;
六:rowid的使用
--rowid:每行记录存放的真实物理地址
select rowid,e.* from emp e;
--例子
--去除表中重复数据
create table p(
name varchar2(10)
);
insert into p values(\'张三\'); --执行3次
insert into p values(\'李四\'); --执行4次
select rowid,p.* from p;
--删除表中记录,只保留rowid最小的记录,一张表当两张表用
DELETE FROM p p1 WHERE rowid > (select min(ROWID) FROM p p2 where p1.name = p2.name);
select rowid,p.* from p;
七:分页查询
/*
oracle:rownum:分页查询
mysql: limit
*/
--查询员工表第6第-10的记录
select rownum hanghao ,emp.* from emp;
select * from (select rownum hanghao ,emp.* from emp) t1 WHERE t1.hanghao between 6 and 10;
八: 集合运算
/*
集合运算:
并集:将两个查询结果进行合并 union 去重和 union all 不去重
交集:
*/
--工资大于1500,或者20号部门以下的员工
select * from emp where sal > 1500 or deptno=20;
--工资大于1500的员工信息
select *from emp where sal > 1500;
--20号部门下的员工信息
select *from emp where deptno = 20;
--并集union
select *from emp where sal > 1500
union
select *from emp where deptno = 20; --9条记录,union去重
--并集union all
select *from emp where sal > 1500
union all
select *from emp where deptno = 20; --12条记录,Union all 不去重
--差集运算
--1981年入职的员工(不包括总裁和经理)
--1.1981年入职的员工
select * from emp where to_char(hiredate,\'yyyy\') =1981;
--1.2查询总裁和经理
select *from emp where job =\'PRESIDENT\' or job= \'MANAGER\';
--差集运算
select * from emp where to_char(hiredate,\'yyyy\') =1981
minus
select *from emp where job =\'PRESIDENT\' or job= \'MANAGER\';