重新学习数据库(3)
数据库学习之高级查询
单元概述
通过本章的学习能够理解MySQL数据库中分组查询的含义,掌握常用分组函数的使用,掌握GROUP BY子句的使用规则,掌握分组后数据结果的条件过滤,掌握SELECT语句执行过程,理解子查询的含义,掌握单行子查询和多行子查询的使用
测试数据脚本:
drop TABLE emp;
drop TABLE dept;
drop TABLE salgrade;
create table dept
(
deptno integer(4) not null,
dname varchar(14),
loc varchar(13)
);
alter table dept add constraint pk_dept primary key (deptno);
create table emp
(
empno integer(4) not null,
ename varchar(10),
job varchar(9),
mgr integer(4),
hiredate date,
sal decimal(7,2),
comm decimal(7,2),
deptno integer(2)
);
alter table emp add constraint pk_emp primary key (empno);
alter table emp add constraint fk_deptno foreign key (deptno) references dept (deptno);
create table salgrade
(
grade integer(1),
losal decimal(7,2),
hisal decimal(7,2)
);
insert into DEPT (DEPTNO, DNAME, LOC) values (10, 'ACCOUNTING', 'NEW YORK');
insert into DEPT (DEPTNO, DNAME, LOC) values (20, 'RESEARCH', 'DALLAS');
insert into DEPT (DEPTNO, DNAME, LOC) values (30, 'SALES', 'CHICAGO');
insert into DEPT (DEPTNO, DNAME, LOC) values (40, 'OPERATIONS', 'BOSTON');
insert into SALGRADE (GRADE, LOSAL, HISAL) values (1, 700, 1200);
insert into SALGRADE (GRADE, LOSAL, HISAL) values (2, 1201, 1400);
insert into SALGRADE (GRADE, LOSAL, HISAL) values (3, 1401, 2000);
insert into SALGRADE (GRADE, LOSAL, HISAL) values (4, 2001, 3000);
insert into SALGRADE (GRADE, LOSAL, HISAL) values (5, 3001, 9999);
-- 下面要特别注意,%d-%m-%Y 里的 d 和 m 一定要小写
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7369, 'SMITH', 'CLERK', 7902, STR_TO_DATE('17-12-1980', '%d-%m-%Y'), 800.00, null, 20);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7499, 'ALLEN', 'SALESMAN', 7698, STR_TO_DATE('20-02-1981', '%d-%m-%Y'), 1600.00, 300.00, 30);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7521, 'WARD', 'SALESMAN', 7698, STR_TO_DATE('22-02-1981', '%d-%m-%Y'), 1250.00, 500.00, 30);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7566, 'JONES', 'MANAGER', 7839, STR_TO_DATE('02-04-1981', '%d-%m-%Y'), 2975.00, null, 20);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7654, 'MARTIN', 'SALESMAN', 7698, STR_TO_DATE('28-09-1981', '%d-%m-%Y'), 1250.00, 1400.00, 30);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7698, 'BLAKE', 'MANAGER', 7839, STR_TO_DATE('01-05-1981', '%d-%m-%Y'), 2850.00, null, 30);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7782, 'CLARK', 'MANAGER', 7839, STR_TO_DATE('09-06-1981', '%d-%m-%Y'), 2450.00, null, 10);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7788, 'SCOTT', 'ANALYST', 7566, STR_TO_DATE('19-04-1987', '%d-%m-%Y'), 3000.00, null, 20);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7839, 'KING', 'PRESIDENT', null, STR_TO_DATE('17-11-1981', '%d-%m-%Y'), 5000.00, null, 10);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7844, 'TURNER', 'SALESMAN', 7698, STR_TO_DATE('08-09-1981', '%d-%m-%Y'), 1500.00, 0.00, 30);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7876, 'ADAMS', 'CLERK', 7788, STR_TO_DATE('23-05-1987', '%d-%m-%Y'), 1100.00, null, 20);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7900, 'JAMES', 'CLERK', 7698, STR_TO_DATE('03-12-1981', '%d-%m-%Y'), 950.00, null, 30);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7902, 'FORD', 'ANALYST', 7566, STR_TO_DATE('03-12-1981', '%d-%m-%Y'), 3000.00, null, 20);
insert into EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
values (7934, 'MILLER', 'CLERK', 7782, STR_TO_DATE('23-01-1982', '%d-%m-%Y'), 1300.00, null, 10);
高级查询单元练习:
1. 查询部门20的员工,每个月的工资总和及平均工资。
SELECT SUM(sal),AVG(sal)
FROM emp
WHERE deptno = 20;
2. 查询工作在CHICAGO的员工人数,最高工资及最低工资。
SELECT COUNT(*),MAX(sal),MIN(sal)
FROM emp e,dept d
WHERE e.deptno = d.deptno
AND d.loc = 'CHICAGO';
3. 查询员工表中一共有几种岗位类型。
SELECT COUNT(DISTINCT job)
FROM emp;
select job
from emp
group by job;
1. 查询每个部门的部门编号,部门名称,部门人数,最高工资,最低工资,工资总和,平均工资。
SELECT d.deptno,d.dname,COUNT(*),MAX(e.sal),MIN(e.sal),SUM(e.sal),AVG(e.sal)
FROM emp e
JOIN dept d
ON e.deptno=d.deptno
GROUP BY deptno;
2. 查询每个部门,每个岗位的部门编号,部门名称,岗位名称,部门人数,最高工资,最低工资,工资总和,平均工资。
select d.deptno,d.dname,e.job,count(*),max(e.sal),min(e.sal),sum(e.sal),avg(e.sal)
from emp e,dept d
where e.deptno=d.deptno
group by d.deptno,d.dname,e.job;
3. 查询每个经理所管理的人数,经理编号,经理姓名,要求包括没有经理的人员信息。
SELECT COUNT(*),m.empno,m.ename
FROM emp e
LEFT outer JOIN emp m
ON e.mgr=m.empno
GROUP BY m.empno;
1. 查询部门人数大于2的部门编号,部门名称,部门人数。
SELECT d.deptno,d.dname,COUNT(*)
FROM emp e,dept d
WHERE e.deptno = d.deptno
GROUP BY d.deptno
HAVING COUNT(*)>2;
select d.deptno,d.dname,count(*)
from emp e
right outer join dept d
on e.deptno=d.deptno
group by d.deptno,d.dname
having count(*)>2;
2. 查询部门平均工资大于2000,且人数大于2的部门编号,部门名称,部门人数,部门平均工资,并按照部门人数升序排序
SELECT d.deptno,d.dname,COUNT(*),AVG(sal)
FROM emp e,dept d
WHERE e.deptno = d.deptno
GROUP BY d.deptno
HAVING COUNT(*)>2 AND AVG(sal)>2000
ORDER BY COUNT(*) ASC;
select d.deptno,d.dname,count(*),avg(e.sal)
from emp e
right outer join dept d
on e.deptno=d.deptno
group by d.deptno,d.dname
having avg(e.sal)>2000 and count(*)>2
order by count(*);
1. 查询入职日期最早的员工姓名,入职日期
SELECT ename,hiredate
FROM emp
WHERE hiredate = (SELECT MIN(hiredate) FROM emp);
2. 查询工资比SMITH工资高并且工作地点在CHICAGO的员工姓名,工资,部门名称
SELECT e.ename,e.sal,d.dname
FROM emp e,dept d
WHERE e.deptno = d.deptno
AND e.sal>(SELECT sal FROM emp WHERE emp.ename = 'SMITH')
AND d.loc = 'CHICAGO';
3. 查询入职日期比20部门入职日期最早的员工还要早的员工姓名,入职日期
SELECT ename,hiredate
FROM emp
WHERE hiredate<(SELECT MIN(hiredate) FROM emp WHERE deptno = 20);
高级查询课后练习:
1. 查询部门平均工资在2500元以上的部门名称及平均工资。
SELECT d.dname,AVG(e.sal)
FROM emp e,dept d
WHERE e.deptno = d.deptno
GROUP BY d.deptno
HAVING AVG(e.sal)>2500;
select d.dname,avg(e.sal)
from dept d
left outer join emp e
on d.deptno=e.deptno
group by d.deptno,d.dname
having avg(e.sal)>=2500;
2. 查询员工岗位中不是以“SA”开头并且平均工资在2500元以上的岗位及平均工资,并按平均工资降序排序。
SELECT job,AVG(sal)
FROM emp
GROUP BY job
HAVING job<> 'SA%'
AND AVG(sal)>=2500
ORDER BY AVG(sal) DESC;
select job,avg(sal)
from emp e
where job not like 'SA%'
group by job
having avg(sal)>=2500
order by avg(sal) desc;
3. 查询部门人数在2人以上的部门名称、最低工资、最高工资。
SELECT d.dname,MIN(e.sal),MAX(e.sal)
FROM emp e,dept d
WHERE e.deptno =d.deptno
GROUP BY d.deptno
HAVING count(*)>2;
select d.dname,round(min(e.sal)),round(max(e.sal))
from emp e
right outer join dept d
on e.deptno=d.deptno
group by d.deptno,d.dname
having count(*)>2;
4. 查询岗位不为SALESMAN,工资和大于等于2500的岗位及每种岗位的工资和。
SELECT job,SUM(sal)
FROM emp
GROUP BY job
HAVING SUM(sal)>=2500
AND job <> 'SALESMAN';
select job,sum(sal)
from emp
where job<>'SALESMAN'
group by job
having sum(sal)>=2500;
5. 显示经理号码和经理姓名,这个经理所管理员工的最低工资,没有经理的KING也要显示,不包括最低工资小于3000的,按最低工资由高到低排序
select m.empno,m.ename,min(e.sal)
from emp e
left outer join emp m
on e.mgr=m.empno
group by m.empno,m.ename
having min(e.sal)>=3000
order by min(e.sal) desc;
6. 查询工资高于编号为7782的员工工资,并且和7369号员工从事相同工作的员工的编号、姓名及工资。
SELECT empno,ename,sal
FROM emp
WHERE sal>(SELECT sal FROM emp WHERE empno = 7782)
AND job = (SELECT job FROM emp WHERE empno = 7369);
7. 查询工资最高的员工姓名和工资。
select ename, sal
from emp
where sal = ( select max(sal) from emp );
8. 查询部门最低工资高于10号部门最低工资的部门的编号、名称及部门最低工资。
SELECT d.deptno,d.dname,MIN(e.sal)
FROM emp e,dept d
WHERE e.deptno = d.deptno
GROUP BY d.deptno
HAVING MIN(e.sal) > (SELECT MIN(sal) FROM emp WHERE deptno = 10);
9. 查询员工工资为其部门最低工资的员工的编号和姓名及工资。
SELECT empno,ename,MIN(sal)
FROM emp
GROUP BY emp.deptno;
10. 显示经理是KING的员工姓名,工资。
SELECT ename,sal
FROM emp
WHERE mgr = (SELECT empno FROM emp WHERE ename='KING');
11. 显示比员工SMITH参加工作时间晚的员工姓名,工资,参加工作时间
SELECT ename,sal,hiredate
FROM emp
WHERE hiredate > (SELECT hiredate FROM emp WHERE ename = 'SMITH');