常见的SQL笔试题和面试题(上):经典50题

CREATE DATABASE SQL50题

GO

USE SQL50题

GO

-- 学生表

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,

PRIMARY KEY(s_id,c_id)

);

GO

-- 插入学生表测试数据

insert into Student values('01' , '赵雷' , '1990-01-01' , '男');

insert into Student values('02' , '钱电' , '1990-12-21' , '男');

insert into Student values('03' , '孙风' , '1990-05-20' , '男');

insert into Student values('04' , '李云' , '1990-08-06' , '男');

insert into Student values('05' , '周梅' , '1991-12-01' , '女');

insert into Student values('06' , '吴兰' , '1992-03-01' , '女');

insert into Student values('07' , '郑竹' , '1989-07-01' , '女');

insert into Student values('08' , '王菊' , '1990-01-20' , '女');

-- 课程表测试数据

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”的课程成绩高的所有学生的学号

算法一:

这个使用了表的自联结

USE SQL50题

SELECT a.s_id

FROM Score a JOIN Score b ON a.s_id=b.s_id

WHERE a.c_id='01' AND b.c_id='02'

AND a.s_score>b.s_score

算法二:

使用子查询

select a.s_id

from (select * from Score where c_id = '01') as a

join (select * from Score where c_id='02') as b

on a.s_id = b.s_id

where a.s_score > b.s_score;

查询学生的学号、修课数、平均分,并按照平均分进行排序。

SELECT s_id '学号',COUNT(*) '课程数',AVG(s_score) '平均分'

FROM Score

GROUP BY s_id

ORDER BY AVG(s_score)

使用分段[100-85],[85-70],[70-60],[<60]来统计各科成绩,分别统计各分数段人数:课程ID和课程名称

SELECT Score.c_id,c_name,

SUM(CASE WHEN s_score BETWEEN 85 AND 100 THEN 1 ELSE 0 END) AS '[100-85]',

SUM(CASE WHEN s_score >=70 and s_score<85 THEN 1 ELSE 0 END) AS '[85-70]',

SUM(CASE WHEN s_score>=60 and s_score<70 THEN 1 ELSE 0 END) AS '[70-60]',

SUM(CASE WHEN s_score<60 THEN 1 ELSE 0 END) AS '[<60]'

FROM Score JOIN Course ON Score.c_id=Course.c_id

GROUP BY Score.c_id,c_name

四、查询出每门课程的及格人数和不及格人数

SELECT c_id,

SUM(CASE WHEN s_score<60 THEN 1 ELSE 0 END) '合格',

SUM(CASE WHEN s_score>=60 THEN 1 ELSE 0 END) '不合格'

FROM Score

GROUP BY c_id

五、查询出每门课程的及格百分比

这个考察了类型转换

SELECT c_id,

(SUM(CAST((CASE WHEN s_score>=60 THEN 1 ELSE 0 END) AS FLOAT))/COUNT(*)) '合格百分比'

FROM Score

GROUP BY c_id

六、查询和“01”号同学所学课程完全相同的其他同学的学号

算法一、

SELECT s_id --选出来所学课程为01学号课程子集的学生
FROM Score
WHERE c_id IN
(SELECT c_id --选出来01学号学的全部课程
FROM Score
WHERE s_id = '01')
AND s_id <> '01'
INTERSECT --取交集
SELECT s_id --选出来和01学号选修课程数相同的学生
FROM Score
WHERE s_id <> '01'
GROUP BY s_id
HAVING COUNT(*) = (SELECT COUNT(*) FROM Score WHERE s_id = '01')

算法二

SELECT s_id --选出来所学课程为01学号子集的学生
FROM Score
WHERE c_id IN
(SELECT c_id --选出来01学号学的全部课程
FROM Score
WHERE s_id = '01')
AND s_id <> '01'
GROUP BY s_id
HAVING COUNT(*) = (SELECT COUNT(*) FROM Score WHERE s_id = '01')

算法一和算法二实质相同,都是先查询选择的课程是01号学生学的课程的子集,在查询选择的课程与01号选择的课程数相同的学生。

最后两者进行取交集。

但是第二种写法更简单。

七、把“SCORE”表中“张三”老师教的课的成绩都更改为此课程的平均成绩

UPDATE Score
SET s_score=
(SELECT AVG(s_score) --算出来平均分
FROM Score
WHERE c_id IN
(SELECT sc.c_id --选出来张三老师教的课
FROM Score sc
JOIN Course co ON sc.c_id = co.c_id
JOIN Teacher te ON te.t_id = co.t_id
WHERE te.t_name = '张三'))
WHERE c_id IN
(SELECT sc.c_id --选出来张三老师教的课
FROM Score sc
JOIN Course co ON sc.c_id = co.c_id
JOIN Teacher te ON te.t_id = co.t_id
WHERE te.t_name = '张三')

在原文还有另外一种解法,但是SQL SERVER不支持:

update Score as a join
(select avg (s_score) as t, Score.c_id from Score
join Course on Score.c_id= Course.c_id
join Teacher on Teacher.t_id= Course.t_id
where t_name ='张三' group by c_id) as b#张三老师教的课与平均分
on a.c_id= b.c_id
set a.s_score = b.t;

八、按各科平均成绩从低到高和及格率的百分数从高到低排列,以如下形式显示:课程号,课程名平均成绩,及格百分数

SELECT c_name '科目',
AVG(s_score) '平均分',
SUM(CAST(CASE WHEN s_score >= 60 THEN 1 ELSE 0 END AS FLOAT)) / COUNT(*) '及格率'
FROM Score
JOIN Course ON Score.c_id = Course.c_id
GROUP BY c_name
ORDER BY AVG(s_score) ASC, SUM(CAST(CASE WHEN s_score >= 60 THEN 1 ELSE 0 END AS FLOAT)) / COUNT(*) DESC

和第五题类似,考察了类型转换,同时还考察了二表连接

九、查询不同老师所教不同课程平均分从高到低显示

SELECT t_name,c_name,AVG(s_score)

FROM Score JOIN Course ON Score.c_id=Course.c_id JOIN Teacher ON Teacher.t_id=Course.t_id

GROUP BY t_name,c_name

ORDER BY AVG(s_score) DESC

考察了分组、聚合函数和三表连接

十、查询各科成绩前三名(包括重复)

要查询前三名,则比其成绩高的人个个数要小于三个。

SELECT st.s_name,co.c_name,sc.c_id

FROM Student st JOIN Score sc ON st.s_id=sc.s_id

JOIN Course co ON sc.c_id=co.c_id

WHERE (SELECT COUNT(*) FROM Score WHERE s_score>sc.s_score AND sc.c_id=c_id)< 3

ORDER BY c_name,sc.c_id

十一、查询学过编号为“01”的课程并且也学过编号为“02”的课程的学生的学号、姓名

这个题的解法比较多,可以通过子查询、自连接、求交集和逻辑和进行求解:

逻辑和

select s_id,s_name

from Student

where s_id in

(select s_id from Score where c_id = '01')

AND s_id in

(select s_id from Score where c_id = '02')

二、自连接

select a.s_id,a.s_name

from Student a JOIN Score b ON a.s_id=b.s_id

JOIN Score c ON a.s_id=c.s_id

where b.c_id='01' and c.c_id='02'

and b.s_id=c.s_id ;