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)代表(學號,課號,成績)
問題:
- 找出沒選過“黎明”老師的所有學生姓名。
- 列出2門以上(含2門)不及格學生姓名及平均成績。
- 即學過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);
參考:小猴子視訊