1. 程式人生 > >12 mysql 練習題

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