SQL經典50題


2023/04/16更新,此專欄50題有很多不嚴謹的地方且不便於測試,建議去牛客網或者LeetCode刷題,有測試用例且更貼近實際業務應用。

50題出自知乎專欄:

圖解SQL面試題:經典50題

SQL面試必會50題

-- 1.查詢課程編號為“01”的課程比“02”的課程成績高的所有學生的學號(重點)
select a.s_id from (select s_id, c_id, s_score as score01 from score where c_id = "01") a
INNER join (select s_id, c_id, s_score as score02 from score where c_id = "02") b 
on a.s_id = b.s_id
where score01 > score02;

-- 2、查詢平均成績大於60分的學生的學號和平均成績(簡單,第二道重點)
select s_id, avg(s_score) as avgs from score
group by s_id
having avgs > 60;

-- 3、查詢所有學生的學號、姓名、選課數、總成績(不重要)
select s_id, count(c_id) as 選課數, sum(s_score) as 總成績 from score GROUP BY s_id;

select s1.s_id as 學號, s_name as 姓名, count(c_id) as 選課數, sum(s_score) as 總成績 from student s1
inner join score s2 
on s1.s_id = s2.s_id
group by s2.s_id;

-- 4、查詢姓“猴”的老師的個數(不重要)
SELECT count(t_id) from teacher where t_name like "猴%";

-- 5、查詢沒學過“張三”老師課的學生的學號、姓名(重點)
-- 學過張三課程的學生id
select s1.s_id from score s1
INNER join course c on s1.c_id = c.c_id
INNER join teacher t on t.t_id = c.t_id
where t_name = "張三";

select * from student where s_id not in (
	select s1.s_id from score s1
	INNER join course c on s1.c_id = c.c_id
	INNER join teacher t on t.t_id = c.t_id
	where t_name = "張三"
);

-- 6、查詢學過“張三”老師所教的所有課的同學的學號、姓名(重點)
-- 20230416更新,經評論提醒更新了解答,先選擇學過張三老師的課的學生學號,通過group by,找到學號出現次數等於張三老師所教課程數的學號。
select s1.s_id, s2.s_name from score s1
INNER JOIN student s2 on s1.s_id = s2.s_id
INNER join course c on s1.c_id = c.c_id
INNER join teacher t on t.t_id = c.t_id
WHERE t.t_id in (
	SELECT t_id FROM teacher
	WHERE teacher.t_name IN ("張三")
)
GROUP BY s1.s_id
HAVING COUNT(s1.s_id) = (
	SELECT COUNT(c_id) FROM teacher t
	INNER join course c on t.t_id = c.c_id
	WHERE t.t_name IN ("張三")
);
-- 原解答
select * from student where s_id in (
	select s1.s_id from score s1
	INNER join course c on s1.c_id = c.c_id
	INNER join teacher t on t.t_id = c.t_id
	where t_name = "張三"
);

-- 7、查詢學過編號為“01”的課程並且也學過編號為“02”的課程的學生的學號、姓名(重點)
select s1.s_id, s_name from score s1
INNER join score s2 on s1.s_id = s2.s_id
INNER join student s on s1.s_id = s.s_id
where s1.c_id = "01" and s2.c_id = "02";

-- 8、查詢課程編號為“02”的總成績(不重點)
select sum(s_score) from score where c_id = "02";

-- 9、查詢所有課程成績小於60分的學生的學號、姓名
-- 考慮 所有課程成績中的最大值也小於60分
select score.s_id, s_name from score 
INNER join student on score.s_id = student.s_id
GROUP BY s_id having max(s_score) < 60;

-- 10.查詢沒有學全所有課的學生的學號、姓名(重點)
-- 考慮 課程數小於課程總數的s_id
select s1.s_id, s_name from score s1
INNER join student s2
on s1.s_id = s2.s_id
group by s_id 
HAVING count(c_id) < (select count(c_id) from course); 

-- 11、查詢至少有一門課與學號為“01”的學生所學課程相同的學生的學號和姓名(重點)
select DISTINCT s1.s_id, s_name from student s1 
INNER join score s2 on s1.s_id = s2.s_id
where c_id in 
(select c_id from score where s_id = "01")
and s1.s_id != "01";

-- 12.查詢和“01”號同學所學課程完全相同的其他同學的學號(重點)
-- 需要確保該同學沒有學過“01”號同學沒學的課程,還需保證課程數相等
select s_id from score 
where s_id != "01" 
and s_id not in (
	select s_id from score where c_id not in (
		select c_id from score where s_id = "01"
    )
)
group by s_id
having count(*) = (
	select count(*) from score where s_id = "01"
);


-- 13、查詢沒學過"張三"老師講授的任一門課程的學生姓名 和47題一樣(重點,能做出來)
select s_id, s_name from student where s_id not in (
	select s.s_id from course c
	INNER join score s on c.c_id = s.c_id
	INNER join teacher t on c.t_id = t.t_id 
	where t.t_name = "張三"
);


-- 15、查詢兩門及其以上不及格課程的同學的學號,姓名及其平均成績(重點)
select s1.s_id, s2.s_name, avg(s_score) as 平均成績 from score s1 
join student s2 on s1.s_id = s2.s_id
where s_score < 60 
GROUP BY s_id
having count(s_score) >= 2;

-- 16、檢索"01"課程分數小於60,按分數降序排列的學生信息(和34題重復,不重點)
select st.* from student st 
INNER join score sc on st.s_id = sc.s_id
where c_id = "01" and s_score < 60
ORDER BY s_score DESC;

-- 17、按平均成績從高到低顯示所有學生的所有課程的成績以及平均成績(重重點與35一樣)
-- 有參考
select s_id "學號",
max(case when c_id = '01' then s_score else null end) as '語文',
max(case when c_id = '02' then s_score else null end) as '數學',
max(case when c_id = '03' then s_score else null end) as '英語',
avg(s_score) as 平均成績 from score GROUP BY s_id
order by 平均成績 desc;

-- 18.查詢各科成績最高分、最低分和平均分:以如下形式顯示:
-- 課程ID,課程name,最高分,最低分,平均分,及格率,中等率,優良率,優秀率
-- 及格為>=60,中等為:70-80,優良為:80-90,優秀為:>=90 (超級重點)

select sc.c_id 課程ID, c_name 課程名稱, max(s_score) 最高分, min(s_score) 最低分, avg(s_score) 平均分,
avg(case when s_score >= 60 then 1.0 else 0.0 end) as 及格率, 
avg(case when s_score >= 70 and s_score < 80 then 1.0 else 0.0 end) as 中等率,
avg(case when s_score >= 80 and s_score < 90 then 1.0 else 0.0 end) as 優良率,
avg(case when s_score >= 90 then 1.0 else 0.0 end) as 優秀率
from score sc 
inner join course c on sc.c_id = c.c_id
group by sc.c_id;

-- 19、按各科成績進行排序,並顯示排名(重點row_number)
select *, ROW_NUMBER() over (ORDER BY s_score DESC) as 排名
from score;

-- 20、查詢學生的總成績並進行排名(不重點)
select s_id, sum(s_score) 總成績
from score
GROUP BY s_id
ORDER BY 總成績 DESC;

-- 21 、查詢不同老師所教不同課程平均分從高到低顯示(不重點)
select c.t_id, t.t_name, avg(s_score) 平均分
from course c 
INNER join score s on c.c_id = s.c_id
INNER join teacher t on c.t_id = t.t_id
GROUP BY s.c_id
ORDER BY 平均分 DESC;

-- 22、查詢所有課程的成績第2名到第3名的學生信息及該課程成績(重要 25類似)
select st.*, sc.s_score, ROW_NUMBER() over (PARTITION BY c_id ORDER BY s_score desc) as ranking
from score sc INNER join student st on sc.s_id = st.s_id;
-- 窗口函數限制不能直接使用ranking列?
select * from (
	select st.*, sc.s_score, ROW_NUMBER() over (PARTITION BY c_id ORDER BY s_score desc) as ranking
	from score sc INNER join student st on sc.s_id = st.s_id
) r
where ranking between 2 and 3;

-- 23、使用分段[100-85],[85-70],[70-60],[<60]來統計各科成績,分別統計:各分數段人數、課程ID和課程名稱(重點和18題類似)
select s.c_id, c.c_name, 
sum(case when s_score <= 100 and s_score >= 85 then 1 else 0 end) "100-85",
sum(case when s_score < 85 and s_score >= 70 then 1 else 0 end) "85-70",
sum(case when s_score < 70 and s_score >= 60 then 1 else 0 end) "70-60",
sum(case when s_score < 60 then 1 else 0 end) "<60"
from score s
INNER join course c on s.c_id = c.c_id
group by s.c_id;

-- 24、查詢學生平均成績及其名次(同19題,重點)
select s_id, avg(s_score) avgs, ROW_NUMBER() over (order by avg(s_score) desc) ranking
from score group by s_id;

-- 25、查詢各科成績前三名的記錄(不考慮成績並列情況)(重點 與22題類似)
select c_id, st.s_name, s_score from
(select s_id, c_id, s_score, row_number() over (partition by c_id order by s_score desc) ranking
from score) s
INNER join student st on s.s_id = st.s_id
where ranking < 4; 

-- 26、查詢每門課程被選修的學生數(不重點)
select c_id, count(c_id) from score
group by c_id;

-- 27、 查詢出只有兩門課程的全部學生的學號和姓名(不重點)
select st.s_id, st.s_name, count(c_id) from student st
INNER join score sc on st.s_id = sc.s_id
group by sc.s_id
having count(c_id) = 2;

-- 28、查詢男生、女生人數(不重點)
select s_sex, count(s_sex) from student group by s_sex;

-- 29 查詢名字中含有"風"字的學生信息(不重點)
select * from student 
where s_name like "%風%";

-- 31、查詢1990年出生的學生名單(重點year)
select * from student 
where year(s_birth) = 1990;

-- 32、查詢平均成績大於等於85的所有學生的學號、姓名和平均成績(不重要)
select st.s_id, st.s_name, avg(s_score) 平均成績 from student st 
INNER join score sc on st.s_id = sc.s_id
GROUP BY st.s_id
having 平均成績 >= 85;

-- 33、查詢每門課程的平均成績,結果按平均成績升序排序,平均成績相同時,按課程號降序排列(不重要)
select c_id, avg(s_score) avgs from score
group by c_id
order by avgs asc, c_id desc;

-- 34、查詢課程名稱為"數學",且分數低於60的學生姓名和分數(不重點)
select s_name, s_score from score sc 
inner join student st on sc.s_id = st.s_id 
inner join course c on sc.c_id = c.c_id 
where c.c_name = "數學" and s_score < 60;

-- 35、查詢所有學生的課程及分數情況(重點)
select s_id, 
max(case when c_name = '數學' then s_score else null end) 數學, 
max(case when c_name = '語文' then s_score else null end) 語文, 
max(case when c_name = '英語' then s_score else null end) 英語 
from score s
INNER join course c on s.c_id = c.c_id
group by s_id;

-- 36、查詢任何一門課程成績在70分以上的姓名、課程名稱和分數(重點)
select st.s_id, s_name, c_name, s_score from student st 
INNER join score sc on st.s_id = sc.s_id
inner join course c on sc.c_id = c.c_id
where s_score > 70;

-- 37、查詢不及格的課程並按課程號從大到小排列(不重點)
select st.s_id, s_name, c_name, sc.c_id, s_score from score sc 
inner join student st on sc.s_id = st.s_id
inner join course c on sc.c_id = c.c_id
where s_score < 60 
order by sc.c_id desc;

-- 38、查詢課程編號為03且課程成績在80分以上的學生的學號和姓名(不重要)
select sc.s_id, st.s_name
from score sc 
inner join student st on sc.s_id = st.s_id
where sc.c_id = "03" and s_score > 80;

-- 39、求每門課程的學生人數(不重要)
select c_id, count(s_id) from score
group by c_id;

-- 40、查詢選修“張三”老師所授課程的學生中成績最高的學生姓名及其成績(重要top)
select s_name, s_score from student st 
inner join score sc on st.s_id = sc.s_id
inner join course c on sc.c_id = c.c_id
inner join teacher t on c.t_id = t.t_id
where t.t_name = "張三"
order by s_score desc
limit 1;

-- 41.查詢不同課程成績相同的學生的學生編號、課程編號、學生成績 (重點)
-- 題意有點模糊,有參考
select distinct s1.s_id, s1.s_score, s1.c_id
from score s1
inner join score s2 
on s1.s_id = s2.s_id
where s1.s_score = s2.s_score and s1.c_id != s2.c_id;


-- 42、查詢每門功課成績最好的前兩名(同22和25題)
select * from (
select s_id, c_id, s_score, ROW_NUMBER() over (PARTITION BY c_id order by s_score desc) ranking
from score) a
where ranking < 3;

-- 43、統計每門課程的學生選修人數(超過5人的課程才統計)。要求輸出課程號和選修人數,查詢結果按人數降序排列,若人數相同,按課程號升序排列(不重要)
select c_id, count(s_id) counts from score
group by c_id
having counts > 5
order by counts desc, c_id asc;

-- 44、檢索至少選修兩門課程的學生學號(不重要)
select s_id, count(c_id) from score 
group by s_id
having count(c_id) >= 2;

-- 45、 查詢選修了全部課程的學生信息(重點划紅線地方)
select st.* from student st 
inner join score sc on st.s_id = sc.s_id
group by s_id
having count(c_id) = (select count(*) from course);

-- 46、查詢各學生的年齡(精確到月份)
/* 時間戳 select from_unixtime(1645707893);
select unix_timestamp(now());*/
select s_name, timestampdiff(month, s_birth, now()) / 12 年齡
from student;


/*
47、48 這兩個周數問題很多,week(day)獲得的是day在該年度的第幾周,不能與其他年份的第幾周比較;
參考 select week("2020-01-05"), week("2018-01-05"); 結果一個為第一周,一個為第0周;
那么判斷生日所在周數需要將年份替換為當前日期的年份,再判斷該日期在now()對應年份的周數; 
關於datediff差值小於7的判斷方法,完全不能保證兩個周數相同,比如周日和周一;
還需要考慮一年中最后一周的情況,這一系列都過於復雜,就不寫了。
*/
-- 47、查詢本周過生日的學生

-- 48、查詢下周過生日的學生

-- 49、查詢本月過生日的學生
select s_name, s_birth from student 
where month(s_birth)  = month(now());

-- 50、查詢下月過生日的學生
select s_name, s_birth from student 
where month(s_birth)  = (month("2020-12-01") + 1) % 12;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM