目录
一、建表语句
员工表
CREATE TABLE `emp` (
`empno` int(11),
`ename` varchar(255) DEFAULT NULL,
`job` varchar(255) DEFAULT NULL,
`mgr` varchar(255) DEFAULT NULL,
`hiredate` date DEFAULT NULL,
`sal` int(11) DEFAULT NULL,
`comm` int(11) DEFAULT NULL,
`deptno` int(11) DEFAULT NULL,
PRIMARY KEY (`empno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800', NULL, '20');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600', '300', '30');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250', '500', '30');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975', NULL, '20');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250', '1400', '30');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850', NULL, '30');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450', NULL, '10');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19', '3000', NULL, NULL);
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7839', 'KING', 'PRESIDENT', NULL, '1981-11-17', '5000', NULL, '10');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300', NULL, '10');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-05-23', '1100', NULL, '20');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000', NULL, '20');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7844', 'TURNER', 'SALESMAN', '7698', '1981-09-08', '1500', NULL, '30');
INSERT INTO `test`.`emp` (`empno`, `ename`, `job`, `mgr`, `hiredate`, `sal`, `comm`, `deptno`) VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950', NULL, '30');
部门表
CREATE TABLE `dept` (
`deptno` int(11),
`dname` varchar(255) DEFAULT NULL,
`loc` varchar(255) DEFAULT NULL,
PRIMARY KEY (`deptno`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`dept` (`deptno`, `dname`, `loc`) VALUES ('10', 'ACCOUNTING', 'NEW YOUK');
INSERT INTO `test`.`dept` (`deptno`, `dname`, `loc`) VALUES ('20', 'RESEARCH', 'DALLAS');
INSERT INTO `test`.`dept` (`deptno`, `dname`, `loc`) VALUES ('30', 'SALES', 'CHICAGO');
INSERT INTO `test`.`dept` (`deptno`, `dname`, `loc`) VALUES ('40', 'OPERATIONS', 'BOSTON');
薪资等级表
CREATE TABLE `salgrade` (
`grade` int(11),
`losal` int(11) DEFAULT NULL,
`hisal` int(11) DEFAULT NULL,
PRIMARY KEY (`grade`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test`.`salgrade` (`grade`, `losal`, `hisal`) VALUES ('1', '700', '1200');
INSERT INTO `test`.`salgrade` (`grade`, `losal`, `hisal`) VALUES ('2', '1201', '1400');
INSERT INTO `test`.`salgrade` (`grade`, `losal`, `hisal`) VALUES ('3', '1401', '2000');
INSERT INTO `test`.`salgrade` (`grade`, `losal`, `hisal`) VALUES ('4', '2001', '3000');
INSERT INTO `test`.`salgrade` (`grade`, `losal`, `hisal`) VALUES ('5', '3001', '9999');
二、多表连接查询
2.1 内连接查询
多表查询:查询员工的员工编号、姓名、薪水和部门编号、部门名称
交叉连接:笛卡尔积,没有实际的意义,有理论的意义,让我们明白连接查询底层的原理
SELECT * FROM emp CROSS JOIN dept
自然连接:会自动的匹配所有的同名列(目前同名列只有deptno),并且同名列只保留一份
最大的有点:简单
SELECT * FROM emp natural JOIN dept
SELECT empno,ename,sal,deptno,dname FROM emp natural JOIN dept
缺点:没有指明各列属于哪个表,效率地下
解决:指定表明
SELECT emp.empno,emp.ename,emp.sal,emp.deptno,dept.dname FROM emp natural JOIN dept
缺点:表明可能比较长
解决:起别名
SELECT e.empno,e.ename,e.sal,e.deptno,d.deptno,d.dname FROM emp e natural JOIN dept d
using子句
natural自然连接的缺点:会自动的按照所有的同名列进行匹配,如果希望只按照某个同名列进行匹配,怎么办?
解决:using子句,注意natural就不要了
SELECT e.empno,e.ename,e.sal,e.deptno,d.deptno,d.dname FROM emp e JOIN dept d USING (deptno)
on子句
natural、using的缺点:必须有同名列,如果有主键、外键不同名,怎么办?
解决:on子句
SELECT e.empno,e.ename,e.sal,e.deptno,d.deptno,d.dname FROM emp e JOIN dept d ON e.deptno = d.deptno
问题:到底使用哪种连接查询
- cross 不用
- natural、using:必须有同名列
- on 不管是否有同名列,均可使用,可读性强
- 建议使用on子句
内连接查询带筛选条件
SELECT
e.empno,
e.ename,
e.sal,
e.deptno,
d.deptno,
d.dname
FROM
emp e
JOIN dept d ON e.deptno = d.deptno
WHERE sal > 2000
ORDER BY sal DESC
内连接查询:只显示匹配的数据,有些员工没有部门,这些员工不会被匹配
2.2 外连接查询
外连接查询:除了显示匹配的数据,还可以匹配全部或者部分不匹配的数据
左外连接 left join:除了显示匹配的数据,还可以显示左表的不匹配数据
SELECT * FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno
右外连接 right join:除了显示匹配的数据,还可以显示右表的不匹配数据
SELECT * FROM emp e RIGHT JOIN dept d ON e.deptno = d.deptno
全外连接 full outer join:除了显示匹配的数据,还可以显示左、右表的不匹配数据
MySQL还不支持全外连接,Oracle支持
变通的解决方案
SELECT * FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno
UNION
SELECT * FROM emp e RIGHT JOIN dept d ON e.deptno = d.deptno
2.3 三表连接查询
多表查询:查询员工的员工编号、姓名、薪水和部门编号、部门名称、薪水等级
第一步:查询员工的员工编号、姓名、薪水和部门编号、部门名称
为什么使用左外连接?SCOTT虽然没有部门,但是他有薪水
SELECT
e.empno,
e.ename,
e.sal,
e.deptno,
d.deptno,
d.dname
FROM
emp e
LEFT JOIN dept d ON e.deptno = d.deptno
第二步:查询员工的员工编号、姓名、薪水和部门编号、部门名称、薪水等级
SELECT
e.empno,
e.ename,
e.sal,
e.deptno,
d.deptno,
d.dname,
sg.*
FROM
emp e
LEFT JOIN dept d ON e.deptno = d.deptno
JOIN salgrade sg ON e.sal BETWEEN sg.losal AND sg.hisal
2.4 自连接查询
查询员工的编号、姓名、上级编号、上级姓名
第一步:查询员工的编号、姓名、上级编号
SELECT empno,ename,mgr FROM emp
第二步:查询员工的编号、姓名、上级编号、上级姓名
SELECT
e.empno,
e.ename,
e.mgr,
m.empno,
m.ename
FROM
emp e -- 员工表
LEFT JOIN emp m -- 上级表
ON e.mgr = m.empno
三、子查询
子查询:查询的嵌套 外查询 子查询
不相关子查询:子查询可以独立运行;先运行子查询,在运行外查询
相关子查询:子查询不可以独立运行;先运行外查询,在运行子查询
3.1 不相关子查询
单行子查询:直接比较即可 < > =
查询所有比CLARK工资高的员工的信息
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename = 'ClARK')
查询工资高于平均工资的雇员名字和工资
SELECT * FROM emp WHERE sal > (SELECT avg(sal) FROM emp)
查询和ClARK同一部门且比他工资高的雇员名字和工资
SELECT ename,sal FROM emp WHERE job = (SELECT job FROM emp WHERE ename = 'ClARK') AND sal > (SELECT sal FROM emp WHERE ename = 'ClARK')
查询职务和SCOTT相同,比SCOTT雇佣时间早的雇员信息
SELECT * FROM emp WHERE job = (SELECT job FROM emp WHERE ename = 'SCOTT') AND hiredate < (SELECT hiredate FROM emp WHERE ename = 'SCOTT')
多行子查询:不可以直接比较,需要借助关键字 in any all
查询工资低于任意一个职务为CLERK的员工工资的雇员信息
SELECT * FROM emp WHERE sal < ANY (SELECT sal FROM emp WHERE job = 'CLERK') AND job != 'CLERK'
查询工资比SALESMAN部门所有的雇员都高,雇员名字和工资
SELECT empno,ename,sal FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE job = 'SALESMAN')
SELECT empno,ename,sal FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE job = 'SALESMAN')
查询部门20中职务同部门10的雇员职务一样的雇员信息
SELECT * FROM emp WHERE deptno = 20 AND job in (SELECT job FROM emp WHERE deptno = 10)
SELECT * FROM emp WHERE deptno = 20 AND job = ANY (SELECT job FROM emp WHERE deptno = 10)
3.2 相关子查询
相关子查询:子查询不可以独立运行;先运行外查询,在运行子查询
好处:简单、功能强大(一些使用不相关子查询不能实现或者实现繁琐的子查询,可以使用相关子查询实现)
查询最高工资的员工(不相关子查询)
SELECT * FROM emp WHERE sal = (SELECT max(sal) FROM emp)
查询本部门最高工资的员工(相关子查询)
SELECT * FROM emp e WHERE sal = (SELECT max(sal) FROM emp WHERE deptno = e.deptno)
查询工资高于其所在部门的平均工资的员工信息(相关子查询)
SELECT * FROM emp e WHERE sal > (SELECT avg(sal) FROM emp WHERE deptno = e.deptno)
四、综合练习
查询每个部门平均薪水的等级(连接查询,子查询,group by)
SELECT
das.*,sg.grade
FROM
(
SELECT
deptno,
avg(sal) asl
FROM
emp
GROUP BY
deptno
) das
JOIN salgrade sg ON das.asl BETWEEN sg.losal AND sg.hisal