50道經典查詢題(含答案與解析)-MySQL版

注: 網上有很多這套經典題,都大同小異,網上很多答案都是錯誤的或者還可以寫的更好,所以寫了這一篇,更多的 目的是做個學習記錄
這些sql全是測試過,可能仍存在不正確的SQL或者有更優的寫法,請各位指出,我虛心請教並更正!

我用的mysql版本是5.7.17,爲了測試不同場景,數據我有所改動,序號也沒對上號,數量無關痛癢,關鍵是自己能學到東西(我一個也沒刪,甚至還加了幾個,我也不知道爲啥對不上號…),

一. 表結構

-- 用工具導出,不美觀,但是方便,直接運行即可
DROP TABLE IF EXISTS course;
CREATE TABLE course (
  CId varchar(10) DEFAULT NULL,
  Cname varchar(10) DEFAULT NULL,
  TId varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO course VALUES ('01','語文','02'),('02','數學','01'),('03','英語','03'),('04','化學','01');


DROP TABLE IF EXISTS stucou;
CREATE TABLE stucou (
  SId varchar(10) DEFAULT NULL,
  CId varchar(10) DEFAULT NULL,
  score decimal(18,1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO stucou VALUES ('01','01',20.0),('01','02',90.0),('01','03',99.0),('02','01',80.0),('02','02',60.0),('02','03',80.0),('03','01',80.0),('03','02',60.0),('03','03',80.0),('04','01',80.0),('04','02',50.0),('04','03',80.0),('05','01',76.0),('05','02',87.0),('06','01',31.0),('06','03',34.0),('07','02',89.0),('07','03',90.0),('03','04',55.0),('08','02',90.0);


DROP TABLE IF EXISTS student;
CREATE TABLE student (
  SId varchar(10) DEFAULT NULL,
  Sname varchar(10) DEFAULT NULL,
  Sage datetime DEFAULT NULL,
  Ssex varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


INSERT INTO student VALUES ('01','趙雷','1990-01-01 00:00:00','男'),('02','錢電','1990-12-21 00:00:00','男'),('03','孫風','1990-12-20 00:00:00','男'),('04','李雲','1990-12-06 00:00:00','男'),('05','周梅','1991-12-01 00:00:00','女'),('06','吳蘭','1992-01-01 00:00:00','女'),('07','鄭竹','1989-01-01 00:00:00','女'),('09','張三','2017-05-20 00:00:00','女'),('10','李四','2017-12-25 00:00:00','女'),('11','李四','2012-06-06 00:00:00','女'),('12','趙六','2013-05-13 00:00:00','女'),('13','孫七','2014-05-12 00:00:00','女'),('08','周八','2017-12-22 00:00:00','男');

DROP TABLE IF EXISTS teacher;
CREATE TABLE teacher (
  TId varchar(10) DEFAULT NULL,
  Tname varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO teacher VALUES ('01','張三'),('02','李四'),('03','王五');

二. 題目

– 1.查詢" 01 “課程比” 02 "課程成績高的學生的信息及課程分數

SELECT s.*,sc.score,sc1.score
FROM stucou sc
INNER JOIN student s ON s.SId=sc.sid AND sc.cid='01'
INNER JOIN stucou sc1 ON sc1.SId = s.SId AND sc1.CId='02'
WHERE sc.score > sc1.score;

– 1.1 查詢同時存在" 01 “課程和” 02 "課程的情況

SELECT sc.CId,sc.score,sc1.CId,sc1.score,sc.SId
FROM  stuCou   sc  
INNER JOIN stucou sc1 ON sc.SId=sc1.SId AND sc1.CId='02' AND  sc.CId='01'

– 1.2 查詢存在" 01 “課程但可能不存在” 02 "課程的情況(不存在時顯示爲 null )

SELECT sc.CId,sc.score,sc1.CId,sc1.score,sc.SId
FROM  stuCou   sc  
LEFT JOIN stucou sc1 ON sc.SId=sc1.SId AND sc1.CId='02'
WHERE sc.CId='01' ;

– 1.3 查詢不存在" 01 “課程但存在” 02 "課程的情況

SELECT sc.CId,sc.score,sc.SId
FROM  stuCou   sc  
INNER JOIN student s ON s.SId = sc.SId
WHERE sc.SId NOT IN (SELECT sc1.SId from stucou sc1 where  sc1.CId = '01')
AND sc.SId IN (SELECT sc1.SId from stucou sc1 where  sc1.CId = '02')

– 2.查詢平均成績大於等於 60 分的同學的學生編號和學生姓名和平均成績

SELECT 
	sc.SId,s.Sname,avg(sc.score)
FROM stucou sc
INNER JOIN student s ON s.SId = sc.SId
GROUP BY sc.SId
HAVING avg(sc.score) >= 60

– 3.查詢在 SC 表存在成績的學生信息

SELECT 
s.*
FROM student s 
WHERE   exists (SELECT 1 FROM stucou WHERE s.SId = SId)

– 4.查詢所有同學的學生編號、學生姓名、選課總數、所有課程的總成績(沒成績的顯示爲 null )

SELECT
	s.SId,s.Sname,count(sc.CId),sum(sc.score)
FROM student s
LEFT JOIN stucou sc ON sc.SId = s.SId
GROUP BY s.SId

– 4.1 查有成績的學生信息

SELECT
	s.SId,s.Sname,count(sc.CId),sum(sc.score)
FROM student s
INNER JOIN stucou sc ON sc.SId = s.SId
GROUP BY s.SId;

– 5.查詢「李」姓老師的數量

SELECT
*
FROM teacher
WHERE Tname LIKE '李%';

– 6.查詢學過「張三」老師授課的同學的信息

SELECT
s.*
FROM student s 
INNER JOIN stucou sc ON sc.SId = s.SId
INNER JOIN course c ON c.CId = sc.CId
INNER JOIN teacher t ON t.TId = c.TId
WHERE t.Tname = '張三';

– 7.查詢沒有學全所有課程的同學的信息

SELECT
	s.*
FROM student s 
LEFT JOIN stucou sc ON sc.SId = s.SId
GROUP BY s.SId
HAVING count(sc.CId) < (SELECT count(1) FROM course);
-- 存在一個課程,有這個課,但是學生沒學,(練習蘊含邏輯運算)
SELECT
	s.*
FROM student s 
WHERE EXISTS (
	SELECT 1 FROM course c
	WHERE NOT EXISTS (
		SELECT 1 FROM stucou sc 
		WHERE sc.CId = c.CId AND s.SId=sc.SId
	)
);

– 8.查詢至少有一門課與學號爲" 01 "的同學所學相同的同學的信息

SELECT
	s.*
FROM student s
INNER JOIN stucou sc ON sc.SId = s.SId
WHERE sc.CId IN (
	SELECT cid FROM stucou WHERE SId = '01'
)
AND s.SId != '01'
GROUP BY s.SId;

– 9.查詢和" 01 "號的同學學習的課程 完全相同的其他同學的信息

網上很多這道題寫的很複雜,或者用判斷課程數的方式來做(這是不正確的),其實這是邏輯運算,涉及到離散數學的知識,詳情解釋:https://blog.csdn.net/qsyzb/article/details/12525955, 前後幾個題我按照這種方式寫了答案,以供練習
此題 抄至:https://www.jianshu.com/p/476b52ee4f1b, 評論區第22樓
在這裏插入圖片描述

		-- 不存在這樣的課程 , 01學了,但是學生x沒學  ->   蘊含邏輯運算
SELECT *
FROM student
WHERE  NOT EXISTS( 
	SELECT * 
	FROM stucou  sc1
	WHERE sc1.SId='01' AND NOT EXISTS( 
		SELECT * 
		FROM stucou sc2 
		WHERE sc2.SId=student.SId AND sc1.CId=sc2.CId)
)
-- and s.sid!='01'  (需要排除01就排除唄)

– 10.查詢沒學過"張三"老師講授的任一門課程的學生姓名

SELECT
	s.*
FROM student s
WHERE NOT EXISTS (
	SELECT 1 FROM stucou sc 
	INNER JOIN course c ON c.CId= sc.CId
	INNER JOIN teacher t ON t.TId= c.TId
	WHERE t.Tname='張三' AND sc.SId = s.SId
)

– 10.1查詢沒學過"張三"老師講授的全部課程的學生姓名

	-- 存在這樣的課程,張三老師教了,但是學生沒學
SELECT
	s.*
FROM student s 
WHERE   EXISTS (
	SELECT 1 FROM teacher t 
	INNER JOIN course c ON  c.TId= t.TId
	WHERE t.Tname='張三' AND  NOT EXISTS (
		SELECT 1 FROM stucou sc 
		WHERE c.CId = sc.CId AND sc.SId=s.SId
	)
)

– 10.2查詢學過"張三"老師講授的全部課程的學生姓名

	-- 不存在這樣的課程,張三老師教了,但是學生沒學
SELECT
	s.*
FROM student s 
WHERE NOT EXISTS (
	SELECT 1 FROM teacher t 
	INNER JOIN course c ON  c.TId= t.TId
	WHERE t.Tname='張三' AND  NOT EXISTS (
		SELECT 1 FROM stucou sc 
		WHERE c.CId = sc.CId AND sc.SId=s.SId
	)
)

– 10.3查詢兩門及其以上不及格課程的同學的學號,姓名及其平均成績

像這種求兩門以上的數據,都可以自聯(左聯),比較大小,判斷個數,後面還有還幾個這樣的題

SELECT
	s.*,avg(sc.score)
FROM student s 
INNER JOIN stucou sc ON sc.sid = s.SId
WHERE EXISTS (
	SELECT * FROM stucou sc1 
	WHERE sc1.score<60  AND s.SId = sc1.SId
	GROUP BY sc1.SId
	HAVING count(sc1.SId)>=2
)
GROUP by s.SId

– 11.檢索" 01 "課程分數小於 60,按分數降序排列的學生信息

SELECT 
	s.*,sc.CId,sc.score
FROM student s 
INNER JOIN stucou sc ON sc.SId= s.SId
WHERE sc.CId='01' AND sc.score < 60
ORDER BY sc.score desc

– 12.按平均成績從高到低顯示所有學生的所有課程的成績以及平均成績

SELECT
	*
FROM  stucou sc  
LEFT JOIN (
	SELECT sc1.SId, avg(sc1.score) avgsc FROM stucou sc1 
	GROUP BY sc1.SId
)r ON   sc.SId=r.SId
ORDER BY sc.SId DESC

– 13.查詢各科成績最高分、最低分和平均分:

SELECT
	sc.CId,min(sc.score),max(sc.score),avg(sc.score)
FROM stucou sc
GROUP BY sc.CId

– 14.以如下形式顯示:課程 ID,課程 name,最高分,最低分,平均分,及格率,中等率,優良率,優秀率 ,選修人數
– 及格爲>=60,中等爲:70-80,優良爲:80-90,優秀爲:>=90
– 要求輸出課程號和選修人數,查詢結果按人數降序排列,若人數相同,按課程號升序排列

SELECT
	sc.CId,c.Cname,max(sc.score),min(sc.score),avg(sc.score),
	sum(CASE  WHEN sc.score>=60 THEN 1 ELSE 0 END )/ count(1) 及格率,
	sum(CASE  WHEN sc.score>=70 AND sc.score<80 THEN 1 ELSE 0 END )/ count(1) 中等率,
	sum(CASE  WHEN sc.score>=80 AND sc.score<90 THEN 1 ELSE 0 END )/ count(1) 優良率,
	sum(CASE  WHEN sc.score>=90 THEN 1 ELSE 0 END )/ count(1) 優秀率,
	count(1) num 
FROM stucou sc 
INNER JOIN course c ON c.CId=sc.CId
GROUP BY c.CId
ORDER BY num DESC,c.CId ASC

– 15.按各科成績進行排序,並顯示排名, Score 重複時保留名次空缺

在oralce中有rank()等開窗函數,在mysql中沒有,可以這樣寫,思路和前面的 求兩門及格的學生 差不多

SELECT
	sc.CId,sc.SId,sc.score,count(sc1.score)+1 num  
FROM stucou sc 
LEFT JOIN stucou sc1 ON sc.CId=sc1.CId AND sc.score < sc1.score -- 用and不用where,在連接時就需過濾,
GROUP BY sc.CId,sc.SId
ORDER BY sc.CId , num  ASC

– 15.1 按各科成績進行排序,並顯示排名, Score 重複時合併名次

解釋見 16.1

SELECT
	sc.CId,sc.SId,sc.score,count(sc1.SId)+1 num  
FROM stucou sc 
LEFT JOIN stucou sc1 ON sc.CId=sc1.CId AND (sc.score < sc1.score OR (sc.score = sc1.score AND sc.SId > sc1.SId)  )
GROUP BY sc.CId,sc.SId
ORDER BY sc.CId ASC , num  ASC

– 16.查詢學生的總成績,並進行排名,總分重複時保留名次空缺

SELECT a.SId, a.sum_score, COUNT(b.SId)+1 AS rank
FROM 
(SELECT SId, SUM(score) AS sum_score FROM stucou SC GROUP BY SId) AS a 
LEFT JOIN (SELECT SId, SUM(score) AS sum_score FROM stucou SC GROUP BY SId) AS b 
ON (a.sum_score<b.sum_score )
GROUP BY a.SId, a.sum_score
ORDER BY rank ASC;

– 16.1 查詢學生的總成績,並進行排名,總分重複時不保留名次空缺

此題抄至: https://www.jianshu.com/p/476b52ee4f1b ,評論區第48樓
在這裏插入圖片描述

SELECT a.SId, a.sum_score, COUNT(b.SId)+1 AS rank
FROM 
(SELECT SId, SUM(score) AS sum_score FROM stucou SC GROUP BY SId) AS a 
LEFT JOIN (SELECT SId, SUM(score) AS sum_score FROM stucou SC GROUP BY SId) AS b 
ON (a.sum_score<b.sum_score OR (a.sum_score=b.sum_score AND a.SId > b.SId)) -- 要算上分數相同,但不是自己的,還不能寫 != ,因爲分數相同不一定因爲自己和別人,還有可能是另外兩個人相同
GROUP BY a.SId, a.sum_score
ORDER BY rank ASC;

– 17.統計各科成績各分數段人數:課程編號,課程名稱,[100-85],[85-70],[70-60],[60-0] 及所佔百分比

SELECT
	c.CId,c.Cname,
	sum(CASE WHEN sc.score >=85 THEN 1 ELSE 0 END) excellent,
	sum(CASE WHEN sc.score <85 AND sc.score >=70 THEN 1 ELSE 0 END) good,
	sum(CASE WHEN sc.score <70 AND sc.score >=60 THEN 1 ELSE 0 END) pass,
	sum(CASE WHEN sc.score <60  THEN 1 ELSE 0 END) fail
FROM stucou sc 
INNER JOIN course c ON c.CId=sc.CId
GROUP BY sc.CId

– 18.查詢各科成績前三名的記錄

SELECT
	sc.*
FROM stucou sc 
LEFT JOIN stucou sc1 ON sc.CId=sc1.CId AND sc.score<sc1.score
GROUP BY sc.CId,sc.SId
HAVING count(sc1.CId)<3
ORDER BY sc.CId, sc.score

– 19.查詢每門課程被選修的學生數

SELECT
	sc.CId,count(1)
FROM stucou sc 
GROUP BY sc.CId

– 20.查詢出只選修兩門課程的學生學號和姓名

SELECT
	s.SId,s.Sname,count(sc.CId)
FROM stucou sc 
INNER JOIN student s ON s.SId=sc.SId
GROUP BY sc.SId
HAVING count(sc.CId) = 2

– 21.查詢男生、女生人數

SELECT
	Ssex,count(1)
FROM student 
GROUP BY Ssex

– 22.查詢名字中含有「風」字的學生信息

SELECT 
	*
FROM student
WHERE Sname LIKE '%風%'

– 23查詢相同姓名學生名單,並統計同名人數

SELECT
	SId,Sname,count(1)
FROM student 
GROUP BY Sname
HAVING count(1) >1

– 24查詢 1990 年出生的學生名單

SELECT
	*
FROM student s
WHERE  YEAR(s.Sage) = '1990'

– 25查詢每門課程的平均成績,結果按平均成績降序排列,平均成績相同時,按課程編號升序排列

SELECT
		sc.CId,avg(sc.score) avgs
FROM stucou sc 
GROUP BY sc.CId
ORDER BY avgs DESC , sc.CId ASC

– 26查詢平均成績大於等於 85 的所有學生的學號、姓名和平均成績

SELECT
	sc.SId,s.Sname, avg(sc.score) avgs
FROM stucou sc 
INNER JOIN student s ON s.SId=sc.SId
GROUP BY sc.SId
HAVING avgs>=85

– 27查詢課程名稱爲「數學」,且分數低於 60 的學生姓名和分數

SELECT
	s.Sname,sc.score,c.CId
FROM stucou sc 
INNER JOIN student s ON s.SId=sc.SId
INNER JOIN course c ON c.CId=sc.CId
WHERE c.Cname='數學' AND sc.score<60

– 28查詢所有學生的課程及分數情況(存在學生沒成績,沒選課的情況)

SELECT 
	s.Sname,sc.CId,sc.score,s.SId
FROM student s 
LEFT JOIN stucou sc ON sc.SId=s.SId

– 29查詢任何一門課程成績在 70 分以上的學生姓名、課程名稱和分數

SELECT 
	s.SId,s.Sname,c.CId,c.Cname,sc.score
FROM stucou sc
INNER JOIN student s ON s.SId=sc.SId
INNER JOIN course c ON c.CId = sc.CId
WHERE NOT EXISTS (
	SELECT 1 FROM stucou sc1 
	WHERE sc1.sId = sc.sId AND sc1.score < 70
)

– 30查詢不及格課程的學生和課程

SELECT 
	s.SId,s.Sname,sc.CId,sc.score
FROM  student s 
INNER JOIN stucou sc ON s.SId=sc.SId AND sc.score<60
GROUP by s.sid,sc.CId

– 31查詢課程編號爲 01 且課程成績在 70 分以上的學生的學號和姓名

SELECT
	s.Sname,s.SId,sc.score
FROM student s
INNER JOIN stucou sc ON sc.SId=s.SId
WHERE sc.CId=01 AND sc.score>70

– 32求每門課程的學生人數

SELECT
	sc.CId,count(1)
FROM stucou  sc
GROUP BY sc.CId

– 33成績不重複,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績

SELECT
	s.SId,max(sc.score)
FROM stucou sc 
INNER JOIN student s ON s.SId=sc.SId
INNER JOIN course c ON c.CId=sc.CId
INNER JOIN teacher t ON t.TId=c.TId
WHERE t.Tname='張三' 

– 34成績有重複的情況下,查詢選修「張三」老師所授課程的學生中,成績最高的學生信息及其成績

SELECT
	s.SId,sc.score
FROM stucou sc 
INNER JOIN student s ON s.SId=sc.SId
INNER JOIN course c ON c.CId=sc.CId
INNER JOIN teacher t ON t.TId=c.TId
LEFT  JOIN stucou sc1 ON sc.CId=sc1.CId   AND  sc.score < sc1.score
WHERE t.Tname='張三' 
GROUP BY sc.SId
HAVING count(sc1.score)<1

– 35查詢不同課程成績相同的學生的學生編號、課程編號、學生成績

SELECT
	sc.SId,sc.CId,sc.score
FROM stucou sc 
INNER JOIN stucou sc1 ON sc.CId!=sc1.CId AND sc.score=sc1.score
GROUP BY sc.SId,sc.CId

– 36查詢每門功成績最好的前兩名

SELECT
	sc.*
FROM stucou sc 
LEFT JOIN stucou sc1 ON sc1.CId=sc.CId AND sc.score<sc1.score
GROUP BY sc.CId,sc.SId
HAVING count(sc.score)<2

– 37統計每門課程的學生選修人數(超過 5 人的課程才統計)。

SELECT
	sc.CId,count(1) num
FROM stucou sc 
GROUP BY sc.CId
HAVING num > 5

– 38檢索至少選修兩門課程的學生學號

SELECT 
	sc.SId,count(1)
FROM stucou sc 
GROUP BY sc.SId

– 39查詢選修了全部課程的學生信息

SELECT
	sc.SId, count(1) num 
FROM stucou sc 
GROUP BY sc.SId
HAVING num = (
	SELECT count(1) FROM course
)

– 40查詢各學生的年齡,只按年份來算

select 
	student.SId as 學生編號 , student.Sname  as  學生姓名 , 
	TIMESTAMPDIFF(YEAR,student.Sage,CURDATE()) as 學生年齡
from student

– 41按照出生日期來算,當前月日 < 出生年月的月日則,年齡減一

SELECT
	s.sname, 
	sum(CASE WHEN  
			date_format(sysdate(),'%m-%d') > date_format(s.sage,'%m-%d') 
		THEN date_format(sysdate(),'%Y') - date_format(s.sage,'%Y') +1 
		ELSE date_format(sysdate(),'%Y') - date_format(s.sage,'%Y')  END )age
FROM student s 
GROUP BY s.SId

– 42查詢本週過生日的學生

– WEEKOFYEAR 得到時間在那一年的第幾周,例如, WEEKOFYEAR(‘2018-02-15’) 得到的是2月15這天在2018是第幾周
SELECT yearweek(sysdate()) --結果:201919 ; 估計得到的是從1990年到sysdate()的週數,值都特別大

SELECT
	 s.*
FROM student s 
WHERE WEEKOFYEAR(concat(date_format(sysdate(),'%Y'),'-',date_format(s.Sage, '%m-%d'))) = WEEKOFYEAR(sysdate());

– 43查詢下週過生日的學生

SELECT
	 s.*
FROM student s 
WHERE WEEKOFYEAR(concat(date_format(sysdate(),'%Y'),'-',date_format(s.Sage, '%m-%d'))) = WEEKOFYEAR(sysdate())+1;

– 44查詢本月過生日的學生

SELECT
	 s.*
FROM student s 
WHERE MONTH(sysdate()) = MONTH(s.Sage)

– 45查詢下月過生日的學生

 SELECT
	 s.*
FROM student s 
WHERE MONTH(sysdate())+1 = MONTH(s.Sage)

https://blog.csdn.net/fashion2014/article/details/78826299 這位博主的文章很熱門,可以看看,個人感覺可以多看評論,正文中還是有許多不正確的地方, 時間截止2019-05-17

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章