SQL 必會50道面試題
練習網站
資料庫中單引號和雙引號的局別
建議資料庫內使用單引號,雙引號一般語言中使用
臨時表?
用臨時表替代子查詢
冷門知識
求長度
select length ('133')
select length (null)
建表插入資料
學生表: Student(s_id,s_name,s_birth,s_sex) –學生編號,學生姓名, 出生年月,學生性別 課程表: Course(c_id,c_name,t_id) – –課程編號, 課程名稱,
根據以上資訊按照下面要求寫出對應的SQL語句。 ps:這些題考察SQL的編寫能力,對於這型別的題目,需要你先把4張表之間的關聯關係搞清楚了,最好的辦法是自己在草稿紙上畫關聯圖,然後再編寫對應的SQL語句就比較容易了。下圖是我在草稿紙上畫的這4張表的關係圖,不好理解,你可以列舉一些資料案例來輔助理解:
案例資料建立參考如下 表名和欄位 –1.學生表
Student(s_id,s_name,s_birth,s_sex) –學生編號,學生姓名, 出生年月,學生性別
–2.課程表
Course(c_id,c_name,t_id) – –
–3.教師表
Teacher(t_id,t_name) –教師編號,教師姓名
–4.成績表
Score(s_id,c_id,s_score) –學生編號,課程編號,分數 測試資料
--建表
--學生表
CREATE TABLE `Student`(
`s_id` VARCHAR(20),
`s_name` VARCHAR(20) NOT NULL DEFAULT '',
`s_birth` VARCHAR(20) NOT NULL DEFAULT '',
`s_sex` VARCHAR(10) NOT NULL DEFAULT '',
PRIMARY KEY(`s_id`)
);
--課程表
CREATE TABLE `Course`(
`c_id` VARCHAR(20),
`c_name` VARCHAR(20) NOT NULL DEFAULT '',
`t_id` VARCHAR(20) NOT NULL,
PRIMARY KEY(`c_id`)
);
--教師表
CREATE TABLE `Teacher`(
`t_id` VARCHAR(20),
`t_name` VARCHAR(20) NOT NULL DEFAULT '',
PRIMARY KEY(`t_id`)
);
--成績表
CREATE TABLE `Score`(
`s_id` VARCHAR(20),
`c_id` VARCHAR(20),
`s_score` INT(3),
PRIMARY KEY(`s_id`,`c_id`)
);
--插入學生表測試資料
insert into Student values('01' , '趙雷' , '1990-01-01' , '男');
insert into Student values('02' , '錢電' , '1990-12-21' , '男');
insert into Student values('03' , '[孫風](https://www.zhihu.com/search?q=孫風&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"article"%2C"sourceId"%3A43289968})' , '1990-05-20' , '男');
insert into Student values('04' , '[李雲](https://www.zhihu.com/search?q=李雲&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"article"%2C"sourceId"%3A43289968})' , '1990-08-06' , '男');
insert into Student values('05' , '[周梅](https://www.zhihu.com/search?q=周梅&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"article"%2C"sourceId"%3A43289968})' , '1991-12-01' , '女');
insert into Student values('06' , '[吳蘭](https://www.zhihu.com/search?q=吳蘭&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"article"%2C"sourceId"%3A43289968})' , '1992-03-01' , '女');
insert into Student values('07' , '[鄭竹](https://www.zhihu.com/search?q=鄭竹&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"article"%2C"sourceId"%3A43289968})' , '1989-07-01' , '女');
insert into Student values('08' , '王菊' , '1990-01-20' , '女');
--[課程表](https://www.zhihu.com/search?q=課程表&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"article"%2C"sourceId"%3A43289968})測試資料
insert into Course values('01' , '語文' , '02');
insert into Course values('02' , '數學' , '01');
insert into Course values('03' , '英語' , '03');
--教師表測試資料
insert into Teacher values('01' , '張三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
--成績表測試資料
insert into Score values('01' , '01' , 80);
insert into Score values('01' , '02' , 90);
insert into Score values('01' , '03' , 99);
insert into Score values('02' , '01' , 70);
insert into Score values('02' , '02' , 60);
insert into Score values('02' , '03' , 80);
insert into Score values('03' , '01' , 80);
insert into Score values('03' , '02' , 80);
insert into Score values('03' , '03' , 80);
insert into Score values('04' , '01' , 50);
insert into Score values('04' , '02' , 30);
insert into Score values('04' , '03' , 20);
insert into Score values('05' , '01' , 76);
insert into Score values('05' , '02' , 87);
insert into Score values('06' , '01' , 31);
insert into Score values('06' , '03' , 34);
insert into Score values('07' , '02' , 89);
insert into Score values('07' , '03' , 98);
第一題
-- 查詢課程編號為01的課程比02的課程成績高的所有學生的學號
SELECT
a.s_id AS "學號",
c.s_name AS "姓名",
a.s_score AS "01",
b.s_score AS "02"
FROM
( SELECT s_id, s_score FROM `score` WHERE c_id = 001 ) a
INNER JOIN ( SELECT s_id, s_score FROM `score` WHERE c_id = 002 ) b ON a.s_id = b.s_id
INNER JOIN student c ON a.s_id = c.s_id
WHERE
a.s_score > b.s_score
第二題
group by 後返回的欄位除分組條件和條件聚合結果(統計值),其他欄位無意義,可能報錯?
-- 查詢平均成績大於60分的學生的學號和平均成績
SELECT
s_id AS "學號",
avg( s_score ) AS score
FROM
`score`
GROUP BY
s_id
HAVING
score > 60
第三題
case when 的用法
-- 查詢所有學生的學號,姓名,選課數,總成績
SELECT
a.s_id AS "學號",
a.s_name AS "姓名",
CASE
WHEN b.count IS NULL THEN
0 ELSE b.count
END AS "課程數",
CASE
WHEN b.sum IS NULL THEN
0 ELSE b.sum
END AS "總成績"
FROM
`student` a
LEFT JOIN ( SELECT s_id, count( c_id ) AS count, sum( s_score ) AS sum FROM `score` GROUP BY s_id ) b ON b.s_id = a.s_id
第四題
-- 查詢姓猴的老師的個數
SELECT
count( DISTINCT ( t_name ) )
FROM
`teacher`
WHERE
t_name LIKE "張%";
第五題
先查學過的,後取反,not in
-- 沒學過張三老師課的學生的學號和姓名
SELECT
s_id,
s_name
FROM
student
WHERE
s_id NOT IN (
SELECT
s_id
FROM
score
WHERE
c_id =(
SELECT
c_id
FROM
course
WHERE
t_id =(
SELECT
t_id
FROM
`teacher`
WHERE
t_name = '張三'
)))
第二種解法
SELECT
s_id,
s_name
FROM
student
WHERE
s_id NOT IN (
SELECT
s_id
FROM
score a
INNER JOIN course b ON a.c_id = b.c_id
INNER JOIN teacher c ON c.t_id = b.t_id
WHERE
c.t_name = "張三")
第六題
-- 查詢學過張三老師所教的所有課的同學的學號,姓名
SELECT
a.s_id,
a.s_name
FROM
`student` a
INNER JOIN `score` b ON a.s_id = b.s_id
INNER JOIN course c ON b.c_id = c.c_id
INNER JOIN `teacher` d ON c.t_id = d.t_id
WHERE
d.t_name = '張三'
第七題
求交集一般用inner join
-- 查詢學過編號為01的課程且學過編號為02的課程的學生的學號,姓名 select b.s_id,c.s_name from(select s_id from score where c_id=01)a inner join(select s_id from score where c_id=02)b on a.s_id=b.s_id inner join student c on b.s_id=c.s_id
第八題
統計函式不分組也能用,統計函式後不要留空格
-- 查詢課程編號為02的總成績 select sum(s_score),avg(s_score) from score where c_id='02'
第九題
-- 查詢所有成績小於60的分的學生學號和姓名
-- 第一步,查詢成績小於60分的成績的同學及不及格課程數
select s_id,count(c_id)as cnt from score where s_score <60 group by s_id;
-- 第二步,查詢每名同學所學課程的數量
select s_id,count(c_id) from score group by s_id;
select c.s_id,c.s_name from (select s_id,count(c_id)as cnt from score where s_score <60 group by s_id) a inner join
(select s_id,count(c_id)as cnt from score group by s_id) b on a.s_id=b.s_id inner join student c on c.s_id=b.s_id
where a.cnt<=b.cnt;
第十題
注意where和having的區別
-- 查詢沒有學全所有課的學生的學號,姓名
-- 第一步,查詢沒有學生學了幾門課
SELECT
a.s_id,
a.s_name,
CASE
WHEN b.cnt IS NULL THEN
0 ELSE b.cnt
END AS cnt
FROM
student a
LEFT JOIN ( SELECT s_id, count( c_id ) AS cnt FROM score GROUP BY s_id ) b ON a.s_id = b.s_id
having
cnt <(
SELECT
count( 1 )
FROM
course)
錯誤答案
-- 查詢沒有學全所有課的學生的學號,姓名
-- 第一步,查詢沒有學生學了幾門課
select s_id,count(c_id) as cnt from score group by s_id ;
-- 第二步
select b.s_id,b.s_name from (select s_id,count(c_id) as cnt from score group by s_id
having cnt<(select count(1) from course)) a
inner join student b
on a.s_id =b.s_id;
第十一題
-- 查詢至少有一門課與學號為01的學生所學課程相同的學生的學號和姓名 SELECT DISTINCT a.s_id, b.s_name FROM score a INNER JOIN student b ON a.s_id = b.s_id WHERE a.c_id IN ( SELECT c_id FROM score WHERE s_id = 01 ) AND a.s_id != 01
第十二題
-- 查詢和01號同學所學課程完全相同的其他同學的學號 SELECT s_id FROM score GROUP BY s_id HAVING count( c_id ) =( SELECT count( c_id ) FROM score WHERE s_id = 01 ) AND s_id != 01 AND s_id != ( SELECT s_id FROM score WHERE c_id NOT IN ( SELECT c_id FROM score WHERE s_id = 01 ));-- 第一步,查詢出與01號學生所學課程數相同的學生 SELECT s_id FROM score GROUP BY s_id HAVING count( c_id ) =( SELECT count( c_id ) FROM score WHERE s_id = 01 ) AND s_id != 01;-- 第二步,查詢出所學課程不在01號學生所學的課程中的學生(排除) SELECT s_id FROM score WHERE c_id NOT IN ( SELECT c_id FROM score WHERE s_id = 01 );
第十五題
-- 查詢兩門及其以上不及格課程的同學的學號,姓名及其平均成績 SELECT a.s_id, a.s_name, avg( c.s_score ) FROM student a INNER JOIN ( SELECT s_id FROM score WHERE s_score < 60 GROUP BY s_id HAVING count( c_id )>= 2 ) b ON a.s_id = b.s_id INNER JOIN score c ON b.s_id = c.s_id GROUP BY c.s_id;-- 第一步,查詢不及格課程有哪些 SELECT s_id FROM score WHERE s_score < 60;
第十六題
-- 檢索01號課程分數小於60,按分數降序排列的學生資訊
SELECT
b.*,
a.s_score
FROM
score a
INNER JOIN student b ON a.s_id = b.s_id
WHERE
a.c_id = 01
AND a.s_score < 60
ORDER BY
a.s_score DESC
第十七題(重點)
-- 按平均成績從高到底顯示所有學生的所有課程的成績及平均成績
SELECT
s_id,
max(case when c_id=01 then s_score else null end) as "01",
max(case when c_id=02 then s_score else null end) as "02",
max(case when c_id=03 then s_score else null end) as "03",
max(case when c_id=04 then s_score else null end) as "04",
avg( s_score ) AS score
FROM
score
GROUP BY
s_id
ORDER BY
score DESC;
第十八題
多表查詢時,如果欄位不重複時,欄位前不用加表字首
-- 查詢各科成績最高分,最低分和平均分:以如下形式顯示:課程id,課程name,最高分,最低分,平均分,及格率,中等率,優良率,優秀率
-- 及格為>=60,中等為:70-80,優良為:80-90,優秀為:>=90
select a.c_id,b.c_name,max(s_score),min(s_score),avg(s_score),
sum(case when s_score>=60 then 1 else 0 end)/count(s_score) as'及格率',
sum(case when s_score>=70 and s_score <80 then 1 else 0 end)/count(s_score) as'中等率',
sum(case when s_score>=80 and s_score <90 then 1 else 0 end)/count(s_score) as'優良率',
sum(case when s_score>=90 then 1 else 0 end)/count(s_score) as'優秀率'
from score a inner join course b on a.c_id=b.c_id group by a.c_id
第十九題
進階
視窗函式
第二十題
中文也可以作欄位別名的
-- 查詢學生的總成績並進行排名 SELECT s_id, sum( s_score ) AS score FROM score GROUP BY s_id ORDER BY score DESC
第二十一題
group by 的位置影響結果嗎
-- 查詢不同老師所教不同課程平均分從高到低顯示 SELECT b.t_id AS "工號", c.t_name AS "老師", b.c_name AS "課程", avg( s_score ) AS 平均分 FROM score a INNER JOIN course b ON a.c_id = b.c_id INNER JOIN teacher c ON c.t_id = b.t_id GROUP BY a.c_id ORDER BY 平均分 DESC;
第二十二題
超綱
-- 查詢所有課程的成績第2名到第3名的學生資訊及該課程成績 select * from(select a.* ,b.c_id,s_score,row_number () over(partition by c_id order by s_score dese) m from score b inner join student a on a.s_id=b.s_id)c where m in (2,3)
第二十三題
-- 使用分段統計各科成績,分別統計各分段人數:課程id和課程名稱
第二十四題
第二十六題
-- 查詢每門課程被選修的學生數
SELECT
a.c_id AS "課程id",
b.c_name AS "名稱",
count( s_id ) AS "學生數"
FROM
score a
INNER JOIN course b ON a.c_id = b.c_id
GROUP BY
a.c_id
第二十七題
-- 查詢出只有兩門課程的全部學生的學號和姓名
SELECT
b.s_id,
b.s_name
FROM
score a
INNER JOIN student b ON a.s_id = b.s_id
GROUP BY
a.s_id
HAVING
count( c_id )=2
-- 查詢出只有兩門課程的全部學生的學號和姓名
SELECT
s_id,
s_name
FROM
student
WHERE
s_id IN ( SELECT s_id FROM score GROUP BY s_id HAVING count( c_id )= 2 )
第二十八題
重點
不用分組也可以用統計函式
-- 查詢男生和女生的人數
SELECT
sum(
IF
( s_sex = '男', 1, 0 )) AS "男生人數",
sum(
IF
( s_sex = '女', 1, 0 )) AS "女生人數"
FROM
student ;
SELECT
sum( CASE WHEN s_sex = '男' THEN 1 ELSE 0 END ) AS "男生人數",
sum( CASE WHEN s_sex = '女' THEN 1 ELSE 0 END ) AS "女生人數"
FROM
student;
SELECT
s_sex,
count( s_id )
FROM
student
GROUP BY
s_sex;
-- 錯誤答案
SELECT
sum(
IF
( s_sex = '男', 1, 0 )) AS "男生人數",
sum(
IF
( s_sex = '女', 1, 0 )) AS "女生人數"
FROM
student
GROUP BY
s_sex;
SELECT
sum( CASE WHEN s_sex = '男' THEN 1 ELSE 0 END ) AS "男生人數",
sum( CASE WHEN s_sex = '女' THEN 1 ELSE 0 END ) AS "女生人數"
FROM
student
GROUP BY
s_sex;
第二十九題
-- 查詢含有風的學生資訊
第三十一題(year函式)
-- 查詢 1990年出生的學生
SELECT
*
FROM
student
WHERE
YEAR ( s_birth )= 1990;
SELECT YEAR
( '190927' );
支援YYYY-MM-DD,YYYYMMDD,YYMMDD,YYYY/MM/DD
第三十二題
-- 查詢平均成績大於等於85的所有學生的學號,姓名,平均成績
SELECT
a.s_id,
b.s_name,
avg( a.s_score ) AS score
FROM
score a
INNER JOIN student b ON a.s_id = b.s_id
GROUP BY
s_id
HAVING
score >= 85;
第三十二題
-- 查詢每門課程的平均成績,結果按平均成績升序排序,平均成績相同時,按課程號降序排列
SELECT
c_id,
avg( s_score ) AS score
FROM
score
GROUP BY
c_id
ORDER BY
score ASC,
c_id DESC;
第三十三題
-- 查詢課程名稱為數學,且分數低於60的學生姓名和分數
SELECT
s_name,
s_score
FROM
score a
INNER JOIN student b ON a.s_id = b.s_id
WHERE
c_id =(
SELECT
c_id
FROM
course
WHERE
c_name = '數學'
)
AND s_score < 60;
第二種解法
-- 查詢課程名稱為數學,且分數低於60的學生姓名和分數
SELECT
s_name,
c_name,
s_score
FROM
score a
INNER JOIN course b ON a.c_id = b.c_id
INNER JOIN student c ON a.s_id = c.s_id
WHERE
b.c_name = '數學'
AND a.s_score < 60
第三十四題
重點
case when 後沒有逗號
-- 查詢課程名稱為數學,且分數低於60的學生姓名和分數
SELECT
s_name,
max( CASE WHEN c_name = '語文' THEN a.s_score ELSE NULL END ) AS "語文",
max( CASE WHEN c_name = '數學' THEN a.s_score ELSE NULL END ) AS "數學",
max( CASE WHEN c_name = '英語' THEN a.s_score ELSE NULL END ) AS "英語",
max( CASE WHEN c_name = '化學' THEN a.s_score ELSE NULL END ) AS "化學"
FROM
score a
INNER JOIN course b ON a.c_id = b.c_id
INNER JOIN student c ON a.s_id = c.s_id
GROUP BY
a.s_id
用sum和max也可以
第三十六題
-- 查詢課程成績在70分以上課程名稱,分數和學生姓名
SELECT
s_name,
c_name,
s_score
FROM
student a
INNER JOIN score b ON a.s_id = b.s_id
INNER JOIN course c ON c.c_id = b.c_id
WHERE
s_score > 70;
注意多對多的情況 join操作會造成資料增多
第三十七題
-- 查詢不及格的課程並按課程號從大到小排列
SELECT
a.s_id,
c.s_name,
b.c_id,
c_name,
a.s_score
FROM
score a
INNER JOIN course b ON a.c_id = b.c_id
INNER JOIN student c ON a.s_id = c.s_id
WHERE
s_score < 60
ORDER BY
c_id DESC
第三十八題
-- 查詢課程編號為03且課程成績在80分以上的學生的學號和姓名
SELECT
a.s_id,
a.s_name,
c.c_id,
c.c_name,
b.s_score
FROM
student a
INNER JOIN score b ON a.s_id = b.s_id
INNER JOIN course c ON b.c_id = c.c_id
WHERE
b.c_id = 03
AND b.s_score > 80
第三十九題
-- 求每門課程的學生人數
第四十題
重點
-- 查詢選修張三老師所教授課程的學生中成績最高的學生姓名及成績
SELECT
d.s_id,
d.s_name,
b.c_id,
b.c_name,
c.s_score,
a.t_id,
a.t_name
FROM
teacher a
INNER JOIN course b ON a.t_id = b.t_id
INNER JOIN score c ON c.c_id = b.c_id
INNER JOIN student d ON d.s_id = c.s_id
WHERE
a.t_name = '張三'
ORDER BY
c.s_score DESC
LIMIT 0,
1;
時間轉換函式
將字串按模式轉成date時間
str_to_date('2022-01-10 17:23:47','%Y-%m-%d %H:%i:%S')
參考資料https://www.cnblogs.com/xiaoxiao075/p/11949668.html