12 mysql 练习题

先初始化数据,数据来源是http://www.monkey1024.com/database/811

执行以上脚本,我将表名和字段都做了修改,改成小写字母了,为了方便看,其实不改的话看上去更简洁

employee表如下:

department表如下:

salarygrade 表如下:

下面的练习题都是根据上述三张表完成,原题目答案多用连接查询完成,我好想大多用子查询完成的,好像连接查询是比子查询看上去简洁一些:

1取得每个部门最高薪水的人员名称

-- 根据部门编号分组,查询出 部门编号对应的部门最大工资
SELECT departmentnumber ,MAX(salary) FROM employee GROUP BY departmentnumber;
-- 将上述查询当作表和employee表连接,连接条件是两张表的部门编号相同,过滤条件是工资等于部门最高工资
 SELECT 
    employeename,newtab.departmentnumber,newtab.maxsalary
	FROM employee e 
	JOIN (SELECT departmentnumber ,MAX(salary)  AS maxsalary FROM employee GROUP BY departmentnumber) AS newtab
	ON e.departmentnumber=newtab.departmentnumber
	WHERE e.salary=newtab.maxsalary ;

2 哪些人的薪水在部门平均薪水之上

-- 查询部门编号,和部门平均工资
SELECT departmentnumber,AVG(salary) FROM employee GROUP BY departmentnumber;
-- employee表和上述查到的表做连接,连接条件是部门编号相等,过滤条件是员工表的薪水大于新表的部门平均工资
SELECT e.employeename ,e.salary,newtab.departmentnumber,newtab.avgsalary  FROM employee e
JOIN 
(SELECT departmentnumber,AVG(salary)  AS avgsalary FROM employee GROUP BY departmentnumber) AS newtab
ON e.departmentnumber=newtab.departmentnumber
WHERE e.salary >newtab.avgsalary;

 3取得部门中(所有人的)平均薪水等级

--第一步按部门编号分组,查询到部门编号和部门平均薪水
--第二部 将薪水表和上述新表做连接,条件是新表的平均薪水在薪水表中的最低薪水和最高薪水之间
SELECT newtab.departmentnumber,s.grade  FROM salarygrade AS s
JOIN 
(SELECT departmentnumber, AVG(salary)  avgsal FROM employee GROUP BY departmentnumber) newtab
ON newtab.avgsal BETWEEN s.lowsalary AND s.highsalary;

4 不用max函数,取得最高薪水

-- 法1:将薪水按降序排列,取第一个即可 
SELECT salary AS maxsalary FROM employee ORDER BY salary DESC LIMIT 1;

5 取得平均薪水最高的部门的部门编号

-- 法1:查询部门编号和部门的平均工资,按降序排列取第一条记录
SELECT departmentnumber,AVG(salary)  AS avgsalary FROM employee GROUP BY departmentnumber ORDER BY avgsalary DESC LIMIT 0,1;
-- 法2:1查询部门编号的部门平均工资
-- 2 在上述临时表中查出最大的部门平均工资
-- 3 从员工表中查部门编号,条件是按部门编号分组后的部门平均工资等于第2步的结果
SELECT departmentnumber,AVG(salary) avgsal FROM employee GROUP BY departmentnumber 
HAVING avgsal=(
SELECT MAX(newtab.avgsalary)
 FROM 
(SELECT departmentnumber,AVG(salary)  AS avgsalary FROM employee GROUP BY departmentnumber) newtab);

6取得平均薪水最高的部门的部门名称

-- 法1:1 查询部门编号和平均工资,按平均工资降序排列,取第一条,即得到平均工资最大的部门编号和部门平均工资
-- 2 将上述临时表和部门表连接查询,条件是两表的部门编号相同
SELECT d.departmentnumber,d.departmentname FROM department d
  JOIN 
  (SELECT departmentnumber, AVG(salary)  AS avgsalary FROM employee GROUP BY departmentnumber ORDER BY avgsalary DESC LIMIT 0,1) newtab
  ON d.departmentnumber=newtab.departmentnumber;
  
-- 法2:1在employee表中按部门编号分组,查询部门编号和部门平均工资,降序取第1条记录中的部门编号
-- 在部门表中查询,条件是部门编号等于第1步的部门编号
SELECT departmentname FROM department 
WHERE
departmentnumber =(SELECT departmentnumber FROM employee GROUP BY departmentnumber ORDER BY AVG(salary) DESC LIMIT 1); 

说明:此题演示了子查询和连接查询没有本质区别,子查询出的结果可以作为一张临时表和其他表做查询

如果查询出的数据只有一列,可以用来做子查询,有多列的话只能用来连接查询

7 求平均薪水的等级最低的部门的部门名称

--1 查询部门编号和部门平均薪水
SELECT departmentnumber,AVG(salary) FROM employee GROUP BY departmentnumber;
-- 2 薪水表和部门表和第1步的临时表,3张表做连接查询
-- 查到每个部门的平均薪水的等级,和部门编号,部门名称
 SELECT t1.departmentnumber ,d.departmentname,s.grade FROM salarygrade s
 JOIN 
 (SELECT departmentnumber,AVG(salary) avgsal FROM employee GROUP BY departmentnumber)  t1
 ON 
 t1.avgsal BETWEEN s.lowsalary AND highsalary 
 JOIN
 department d
 ON t1.departmentnumber=d.departmentnumber;
--3 查询到平均薪水等级中最低的等级,将按部门编号分组后求得的平均薪水和薪水表连接查询,找出最低的部门平均薪水等级
 SELECT MIN(s.grade)
 FROM  (SELECT AVG(salary) AS avgsalary FROM employee e GROUP BY departmentnumber ) t
 JOIN
 salarygrade s
 ON
 t.avgsalary BETWEEN s.lowsalary AND s.highsalary; 
 -- 4 从第2步的结果中查询最低等级对应的部门名称,即从第2步生成的临时表中查平均薪水等级最低的部门名称,条件是第2步临时表中部门编号等于第3步的结果
  SELECT tt1.departmentname
  FROM 
	(
	SELECT t1.departmentnumber ,d.departmentname,s.grade FROM salarygrade s
	 JOIN 
	 (SELECT departmentnumber,AVG(salary) avgsal FROM employee GROUP BY departmentnumber)  t1
	 ON 
	 t1.avgsal BETWEEN s.lowsalary AND highsalary 
	 JOIN
	 department d
	 ON t1.departmentnumber=d.departmentnumber ) tt1
WHERE
   tt1.grade=(SELECT MIN(s.grade)
	 FROM  (SELECT AVG(salary) AS avgsalary FROM employee e GROUP BY departmentnumber ) t
	 JOIN
	 salarygrade s
	 ON
	 t.avgsalary BETWEEN s.lowsalary AND s.highsalary )  ;
  

8取得比普通员工(员工编号没有在mgr上出现的)的最高薪水还要高的经理人(是指出现在manager字段的员工编号的)姓名

--1在employee表 查询manager编号,去除null元素
SELECT DISTINCT manager FROM employee WHERE manager IS NOT NULL;
-- 2查询员工编号没在manager列出现过的员工的最大工资
SELECT MAX(salary) FROM employee WHERE employeenumber NOT IN (SELECT DISTINCT manager FROM employee WHERE manager IS NOT NULL);
-- 3先将manager编号查询出来作为临时表,和employee做连接查询,连接条件是employee表中的员工编号等于临时表的manager编号,
-- (说明这些员工编号都是manager出现过的人),过滤条件是这些manager中工资大于第2步结果
SELECT e1.employeename 
FROM employee e1
JOIN
(SELECT DISTINCT(manager) AS mgr FROM employee WHERE manager IS NOT NULL ) AS t
ON e1.employeenumber=t.mgr
WHERE e1.salary>(
    SELECT MAX(salary) FROM employee WHERE employeenumber NOT IN (SELECT DISTINCT manager FROM employee WHERE manager IS NOT NULL)	
		);

9取得每个薪水等级有多少员工

-- 1 employee表和薪水等级表连接查询出员工编号和薪水等级
SELECT e.employeenumber AS empn,s.grade AS grade FROM employee e JOIN salarygrade s ON e.salary BETWEEN s.lowsalary AND s.highsalary;
 -- 2 从第1步生成的临时表中查询出工资等级和每个等级的人数
 SELECT grade,COUNT(empn) 
 FROM 
 (SELECT e.employeenumber AS empn,s.grade AS grade 
	FROM employee e
	JOIN salarygrade s 
	ON e.salary BETWEEN s.lowsalary AND s.highsalary) AS newtab
GROUP BY grade;

10列出受雇日期早于其直接上级的所有员工编号、姓名

-- 两张employee表做内连接,连接条件表1的manager等于表2的员工编号,过滤条件是员工的受雇日期小于manager的受雇日期
SELECT e1.employeenumber ,e1.employeename 
FROM employee e1 
JOIN employee e2
ON e1.manager=e2.employeenumber
WHERE e1.hiredate<e2.hiredate;

11列出至少有5个员工的部门名称

-- 1在employee表中按员工编号分组,找出雇员大于5的部门编号
SELECT departmentnumber FROM employee GROUP BY departmentnumber HAVING COUNT(employeename) >=5;

-- 2第1步生成的临时表和部门表做连接查询,连接条件是部门编号相等,查出部门编号和部门名称
SELECT d.departmentnumber,d.departmentname  
FROM department d
JOIN  
(SELECT departmentnumber FROM employee GROUP BY departmentnumber HAVING COUNT(employeename)>=5) AS newtab
ON d.departmentnumber=newtab.departmentnumber;

12列出最低薪水大于1500的工作及从事此工作的雇员人数

-- 在employee表中按工作分组,查询工作名称和该工作的最低工资,以及该工作的员工数
--过滤条件是该工作的员工数大于等于5
SELECT job ,MIN(salary) minsalary ,COUNT(*) FROM employee GROUP BY job HAVING minsalary>1500;

13列出在部门“SALES”工作的员工的姓名

-- 第1步,查询部门名称是'SALES'的部门编号
--2 从employee表中查询员工姓名,过滤条件是其部门编号等于第1步子查询的结果
SELECT employeename  FROM employee WHERE departmentnumber=(SELECT departmentnumber FROM department WHERE departmentname='SALES');

14求部门名称中带“S”字符的部门员工的工资合计、部门人数

-- 1从department表中查询出部门名称中带'S'的部门编号
SELECT departmentnumber FROM department WHERE departmentname LIKE '%S%';
-- 2 将employee表和第1步生成的临时表做右连接,条件是部门编号相等,再按临时表的部门编号分组,查询出部门名称,部门工资之和,部门员工数                 
SELECT newtab.departmentname,SUM(e.salary),COUNT(e.employeename)
FROM employee e
 RIGHT JOIN
 (SELECT departmentnumber ,departmentname FROM department WHERE departmentname LIKE '%S%') AS newtab 
 ON e.departmentnumber=newtab.departmentnumber GROUP BY newtab.departmentname ;
 
 --法2 将employee表和department表做右连接,连接条件是部门编号相等,过滤条件是部门名称中带'S'的部门,再按部门名称分组,查询出部门名称,部门工资之和,和部门员工数
 SELECT d.departmentname,SUM(salary),COUNT(e.employeename) 
 FROM employee e
 RIGHT JOIN 
 department d
 ON e.departmentnumber=d.departmentnumber
 WHERE d.departmentname LIKE '%S%'
 GROUP BY d.departmentname ;

15

有3个表S(学生表),C(课程表),SC(学生选课表),其中

S(SNO,SNAME)代表(学号,姓名)
C(CNO,CNAME,CTEACHER)代表(课号,课名,教师)
SC(SNO,CNO,SCGRADE)代表(学号,课号,成绩)
问题:

  1. 找出没选过“黎明”老师的所有学生姓名。
  2. 列出2门以上(含2门)不及格学生姓名及平均成绩。
  3. 即学过1号课程又学过2号课所有学生的姓名。

初始化数据:

DROP TABLE IF EXISTS SC;
CREATE TABLE SC(
SNO VARCHAR(200),
CNO VARCHAR(200),
SCGRADE VARCHAR(200)
);
DROP TABLE IF EXISTS S;
CREATE TABLE S(
SNO VARCHAR(200 ),
SNAME VARCHAR(200)
);
DROP TABLE IF EXISTS C;
CREATE TABLE C(
CNO VARCHAR(200),
CNAME VARCHAR(200),
CTEACHER VARCHAR(200)
);
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '1', '语文', '张'); 
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '2', '政治', '王'); 
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '3', '英语', '李'); 
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '4', '数学', '赵'); 
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '5', '物理', '黎明'); 

INSERT INTO S ( SNO, SNAME ) VALUES ( '1', '学生1'); 
INSERT INTO S ( SNO, SNAME ) VALUES ( '2', '学生2'); 
INSERT INTO S ( SNO, SNAME ) VALUES ( '3', '学生3'); 
INSERT INTO S ( SNO, SNAME ) VALUES ( '4', '学生4');  

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '1', '40'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '2', '30'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '3', '20'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '4', '80'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '5', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '1', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '2', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '3', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '4', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '5', '40'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '3', '1', '60'); 
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '3', '3', '80'); 

1找出没选过“黎明”老师的所有学生姓名。

--1 查询出黎明老师的可号
SELECT CNO FROM C WHERE CTEACHER='黎明';
-- 2先找出选过黎明老师课号的学生学号
SELECT DISTINCT SNO FROM SC WHERE CNO NOT IN (SELECT CNO FROM C WHERE CTEACHER='黎明');
--3从学生表上找学号不等于上述学号的学生,(有些学生可能没在选课表上)
SELECT SNAME FROM S WHERE SNO NOT IN (SELECT DISTINCT SNO FROM SC WHERE CNO  IN (SELECT CNO FROM C WHERE CTEACHER='黎明'));

2 列出2门以上(含2门)不及格学生姓名及平均成绩

-- 1 在SC表上按学号分组,查找出不及格数大于等于两门的学号
SELECT SNO,COUNT(*) FROM SC WHERE SCGRADE<60 GROUP BY SNO HAVING COUNT(*)>=2;
-- 2 在S表上查找学生姓名,条件是学号在第一步查询的结果之中
 SELECT SNAME FROM S WHERE SNO IN (SELECT SNO FROM SC WHERE SCGRADE<60 GROUP BY SNO HAVING COUNT(*)>=2);
-- 3 将S表和第1步的临时表再和SC表做连接查询,连接条件是学号相等,再按学号分组,找出该学号的姓名,平均成绩
 SELECT SNAME,AVG(scgrade) 
     FROM S
     JOIN (SELECT SNO FROM SC WHERE SCGRADE<60 GROUP BY SNO HAVING COUNT(*)>=2) AS newtab
     ON  S.SNO=newtab.SNO
     JOIN SC
     ON newtab.SNO=SC.SNO
     GROUP BY SC.SNO;

3即学过1号课程又学过2号课所有学生的姓名。

-- 1 在SC表中查询选过课号为1的学号
SELECT SNO FROM SC WHERE CNO=1;
-- 2在SC表上查询选过课号为2的学号
SELECT SNO FROM SC WHERE CNO=2;
-- 3 将上述两张临时表做连接查询,连接条件是学号相等,查询两张临时表交集的学号,
-- 再从S表中查找学生姓名,条件是学号等于前面查到的学号
SELECT SNAME FROM S WHERE SNO
IN (SELECT t1.SNO FROM 
	(SELECT SNO FROM SC WHERE CNO=1) t1
	 JOIN 
	 (SELECT SNO FROM SC WHERE CNO=2)t2 
	 ON
	 t1.SNO=t2.SNO);

参考:小猴子视频

原文:http://www.monkey1024.com/database/844

猜你喜欢

转载自blog.csdn.net/sinat_41132860/article/details/84975148