SQL语句练习
Posted ~无关风月~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL语句练习相关的知识,希望对你有一定的参考价值。
sql面试题(学生表课程表成绩表_教师表)
建表
CREATE TABLE `t_student` (
`student_id` int(11) NOT NULL AUTO_INCREMENT,
`student_name` varchar(32) DEFAULT NULL,
`student_age` int(11) DEFAULT NULL,
`student_sex` varchar(8) DEFAULT NULL,
PRIMARY KEY (`student_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_course` (
`course_id` int(11) NOT NULL AUTO_INCREMENT,
`course_name` varchar(32) DEFAULT NULL,
`teacher_id` int(11) DEFAULT NULL,
PRIMARY KEY (`course_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_score` (
`score_id` int(11) NOT NULL AUTO_INCREMENT,
`student_id` int(11) DEFAULT '0',
`course_id` int(11) DEFAULT NULL,
`score_number` int(11) DEFAULT NULL,
PRIMARY KEY (`score_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `t_teacher` (
`teacher_id` int(11) NOT NULL AUTO_INCREMENT,
`teacher_name` varchar(16) DEFAULT NULL,
PRIMARY KEY (`teacher_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
DEFALUT 定义列的默认值
AUTO_INCREMENT=1 主键自动增长,从1开始增长
插入测试数据语句
INSERT INTO `t_student` VALUES ('1', '刘一', '18', '男');
INSERT INTO `t_student` VALUES ('2', '钱二', '19', '女');
INSERT INTO `t_student` VALUES ('3', '张三', '17', '男');
INSERT INTO `t_student` VALUES ('4', '李四', '18', '女');
INSERT INTO `t_student` VALUES ('5', '王五', '17', '男');
INSERT INTO `t_student` VALUES ('6', '赵六', '19', '女');
INSERT INTO `t_course` VALUES ('1', '语文', '1');
INSERT INTO `t_course` VALUES ('2', '数学', '2');
INSERT INTO `t_course` VALUES ('3', '英语', '3');
INSERT INTO `t_course` VALUES ('4', '物理', '4');
INSERT INTO `t_score` VALUES ('1', '1', '1', '56');
INSERT INTO `t_score` VALUES ('2', '1', '2', '78');
INSERT INTO `t_score` VALUES ('3', '1', '3', '67');
INSERT INTO `t_score` VALUES ('4', '1', '4', '58');
INSERT INTO `t_score` VALUES ('5', '2', '1', '79');
INSERT INTO `t_score` VALUES ('6', '2', '2', '81');
INSERT INTO `t_score` VALUES ('7', '2', '3', '92');
INSERT INTO `t_score` VALUES ('8', '2', '4', '68');
INSERT INTO `t_score` VALUES ('9', '3', '1', '91');
INSERT INTO `t_score` VALUES ('10', '3', '2', '47');
INSERT INTO `t_score` VALUES ('11', '3', '3', '88');
INSERT INTO `t_score` VALUES ('12', '3', '4', '56');
INSERT INTO `t_score` VALUES ('13', '4', '2', '88');
INSERT INTO `t_score` VALUES ('14', '4', '3', '90');
INSERT INTO `t_score` VALUES ('15', '4', '4', '93');
INSERT INTO `t_score` VALUES ('16', '5', '1', '46');
INSERT INTO `t_score` VALUES ('17', '5', '3', '78');
INSERT INTO `t_score` VALUES ('18', '5', '4', '53');
INSERT INTO `t_score` VALUES ('19', '6', '1', '35');
INSERT INTO `t_score` VALUES ('20', '6', '2', '68');
INSERT INTO `t_score` VALUES ('21', '6', '4', '71');
INSERT INTO `t_teacher` VALUES ('1', '叶平');
INSERT INTO `t_teacher` VALUES ('2', '贺高');
INSERT INTO `t_teacher` VALUES ('3', '杨艳');
INSERT INTO `t_teacher` VALUES ('4', '周磊');
问题:
1、查询“001”课程比“002”课程成绩高的所有学生的学号;
SELECT a.student_id FROM
(SELECT student_id,score_number FROM t_score WHERE course_id=001) a,
(SELECT student_id,score_number FROM t_score WHERE course_id=002) b
WHERE a.score_number>b.score_number AND a.student_id=b.student_id;
子查询
SELECT a.student_id
from t_score AS a
WHERE a.course_id=001 AND a.score_number>(
SELECT b.score_number FROM t_score AS b
WHERE b.course_id=002 AND a.student_id=b.student_id
);
SELECT a.student_id
from t_score AS a
WHERE a.course_id=001 AND student_id IN(
SELECT student_id FROM t_score AS b
WHERE b.course_id=002 AND a.score_number>b.score_number AND a.student_id=b.student_id
);
内连接
SELECT a.student_id
FROM t_score AS a
INNER JOIN t_score AS b
ON a.course_id=001 AND b.course_id=002 AND a.score_number>b.score_number AND a.student_id=b.student_id;
等值连接
SELECT a.student_id
from t_score AS a,t_score AS b
WHERE a.course_id=001 AND b.course_id=002 AND a.score_number>b.score_number AND a.student_id=b.student_id ;
交叉连接
SELECT a.student_id
FROM t_score AS a
CROSS JOIN t_score AS b
ON a.course_id=001 AND b.course_id=002 AND a.score_number>b.score_number AND a.student_id=b.student_id;
INNER JOIN 和 等值连接可以有相同的效果,但
INNER JOIN可以不等: select * from t1 inner join t2 on t1.id<>t2.id;
从集合论角度看:等值连接是内连接的子集
CROSS JOIN 做笛卡尔积可以不加 ON 后面的条件,RIGHT JOIN和LEFT JOIN必须加
CROSS JOIN 可以和INNER JOIN 以及 等值连接有相同的效果,但join的方式不同,cross join生成的是先生成笛卡尔集,然后on连接条件被视为了filter用于数据过滤,inner join是直接基于join condition做连接,生成的join集合就是最终的输出结果,产生的中间数据更小。实际上mysql优化器会将这两条查询都优化成同一种join方式。
2、查询平均成绩大于60分的同学的学号和平均成绩;
SELECT student_id,AVG(score_number)
FROM t_score
GROUP BY student_id HAVING AVG(score_number)>60;
group by() 对数据进行分组,对执行完group by之后的组进行聚合函数计算,计算每一个组的值。
group by语句中select指定的字段必须是“分组依据字段”,其他字段若想出现在select中则必须包含在聚合函数中
group by 会根据分组依据,没项只列一行
最后用having 去掉不符合条件的组。
如果根据多列进行分组,用 group by all
聚合函数是对一组值进行计算并返回单一的值的函数,通常与select语句中的group by 子句一同使用。
avg()、max()、min()、sum()、count()
Having与Where的区别
where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,where条件中不能包含聚组函数,使用where条件过滤出特定的行。
having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having 条件过滤出特定的组,也可以使用多个分组标准进行分组。
3、查询所有同学的学号、姓名、选课数、总成绩;
SELECT t_student.student_id,t_student.student_name,COUNT(t_score.course_id),SUM(t_score.score_number)
FROM t_student
LEFT OUTER JOIN t_score ON t_student.student_id=t_score.student_id
GROUP BY student_id ;
SELECT t_student.student_id,t_student.student_name,COUNT(t_score.course_id),SUM(t_score.score_number)
FROM t_student,t_score
WHERE t_student.student_id=t_score.student_id
GROUP BY student_id ;
在上面语句中,实际上是创建了两张表的笛卡尔积,低效利用数据库资源,有些数据库系统会识别出 WHERE连接并自动转换为 INNER JOIN
4、查询姓“李”的老师的个数;
SELECT COUNT(DISTINCT(teacher_name)) AS 个数
FROM t_teacher
WHERE teacher_name LIKE '李%';
加DISTINCT() 是为了防止有重复行
5、查询没学过“叶平”老师课的同学的学号、姓名;
SELECT student_id,student_name
FROM t_student
WHERE student_id NOT IN
(SELECT DISTINCT(student_id)
FROM t_score,t_course,t_teacher
WHERE t_score.course_id=t_course.course_id
AND t_course.teacher_id=t_teacher.teacher_id
AND t_teacher.teacher_name='叶平');
6、查询学过“001”并且也学过编号“002”课程的同学的学号、姓名;
SELECT t_student.student_id,t_student.student_name
FROM t_student,t_score
WHERE t_student.student_id=t_score.student_id
AND t_score.course_id=001
AND EXISTS
(SELECT * FROM t_score AS t_score2 WHERE t_score.student_id=t_score2.student_id AND t_score2.course_id=002)
;
7、查询学过“叶平”老师所教的所有课的同学的学号、姓名;
SELECT student_id,student_name FROM t_student WHERE student_id IN
(
SELECT student_id FROM t_score,t_course,t_teacher WHERE t_score.course_id=t_course.course_id AND t_course.teacher_id=t_teacher.teacher_id AND t_teacher.teacher_name='叶平'
GROUP BY student_id HAVING COUNT(t_course.course_id)=
(SELECT COUNT(course_id) FROM t_course,t_teacher WHERE t_teacher.teacher_id=t_course.teacher_id AND t_teacher.teacher_name='叶平')
);
8、查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号、姓名;
SELECT student_id,student_name FROM t_student WHERE student_id IN
(
SELECT student_id FROM t_score WHERE course_id=002 AND score_number < (SELECT score_number from t_score AS t_score2 WHERE t_score.student_id=t_score2.student_id AND t_score2.course_id=001)
);
SELECT student_id,student_name FROM
(
SELECT t_student.student_id,t_student.student_name,score_number,
(SELECT score_number FROM t_score AS t_score2 WHERE t_score2.student_id=t_student.student_id AND t_score2.course_id=002)score_number2
from t_student,t_score
WHERE t_student.student_id=t_score.student_id AND course_id=001
)derived_table
WHERE score_number2<score_number;
9、查询所有课程成绩都小于60分的同学的学号、姓名;
考虑到从t_score表统计每门课都小于60分的同学的id比较困难,运用反向思维,查询成绩大于等于60分同学的id,不在这里面的即为每门课都小于60分的同学
SELECT student_id,student_name FROM t_student WHERE student_id NOT IN
(
SELECT DISTINCT(student_id) FROM t_score WHERE score_number>=60
)
;
10、查询没有学全所有课的同学的学号、姓名;
SELECT student_id,student_name FROM t_student WHERE student_id IN(
SELECT student_id FROM t_score GROUP BY student_id HAVING COUNT(course_id)<(SELECT COUNT(course_id) FROM t_course)
);
SELECT t_student.student_id,student_name FROM t_student,t_score WHERE t_student.student_id=t_score.student_id
GROUP BY t_student.student_id
HAVING COUNT(course_id)<(SELECT COUNT(course_id) FROM t_course);
11、查询至少有一门课与学号为“001”的同学所学相同的同学的学号和姓名;
SELECT DISTINCT(t_student.student_id),student_name FROM t_student,t_score WHERE t_student.student_id=t_score.student_id AND course_id IN
(
SELECT course_id FROM t_score WHERE student_id=001
);
12、查询至少学过学号为“001”同学所有一门课的其他同学学号和姓名;
此题与上题的唯一区别就是排除学号为“001”的同学本身。
SELECT DISTINCT(t_student.student_id),student_name FROM t_student,t_score WHERE t_student.student_id=t_score.student_id AND course_id IN
(
SELECT course_id FROM t_score WHERE student_id=001
) AND t_student.student_id!=001;
13、把“SC”表中“叶平”老师教的课的成绩都更改为此课程的平均成绩;
UPDATE t_score SET score_number=(
SELECT * from (SELECT AVG(t_score2.score_number) FROM t_score AS t_score2, t_course AS t_course2,t_teacher AS t_teacher2 WHERE t_score2.course_id=t_course2.course_id AND t_course2.teacher_id=t_teacher2.teacher_id AND teacher_name='叶平')ta)
WHERE t_score.course_id=(SELECT course_id FROM t_course WHERE teacher_id=(SELECT teacher_id from t_teacher where teacher_name='叶平'));
此题不好,如果叶平这个老师教多门课就无法更改
14、查询也选了“002”号的同学学习课程的其他同学学号和姓名;
SELECT t_score.student_id,t_student.student_name FROM t_score,t_student WHERE
t_score.course_id IN
(SELECT course_id FROM t_score WHERE student_id=002)
AND
t_score.student_id=t_student.student_id
AND
t_score.student_id!=002
GROUP BY student_id
HAVING COUNT(*)=(SELECT COUNT(*) FROM t_score WHERE student_id=002)
15、删除学习“叶平”老师课的SC表记录;
DELETE t_score FROM t_score,t_course,t_teacher WHERE t_score.course_id=t_course.course_id AND t_course.teacher_id=t_teacher.teacher_id AND teacher_name='叶平'
16、向t_score表中插入一些记录,这些记录字段如下:没有上过编号“003”课程的同学学号、2、002 号课的平均成绩;
INSERT INTO
t_score(student_id,course_id,score_number)
VALUES(
SELECT
student_id,002,(SELECT AVG(score_number) FROM t_score WHERE course_id=002)
FROM t_student WHERE student_id NOT IN (SELECT student_id FROM t_score WHERE course_id=003)
);
17、按平均成绩从高到低显示所有学生的四门的课程成绩,按如下形式显示: 学生ID,语文,数学,英语,物理,有效课程数,有效课程平均分。
SELECT
student_id AS 学生ID,
(SELECT score_number FROM t_score WHERE t_score.student_id=t.student_id AND t_score.course_id=(SELECT course_id FROM t_course WHERE course_name='语文'))AS 语文,
(SELECT score_number FROM t_score WHERE t_score.student_id=t.student_id AND t_score.course_id=(SELECT course_id FROM t_course WHERE course_name='数学'))AS 数学,
(SELECT score_number FROM t_score WHERE t_score.student_id=t.student_id AND t_score.course_id=(SELECT course_id FROM t_course WHERE course_name='英语')) AS 外语,
(SELECT score_number FROM t_score WHERE t_score.student_id=t.student_id AND t_score.course_id=(SELECT course_id FROM t_course WHERE course_name='物理')) AS 物理,
COUNT(*) AS 有效课程数,
AVG(t.score_number) AS 有效课程平均分
FROM t_score AS t
GROUP BY student_id
ORDER BY AVG(t.score_number) DESC;
18、查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分
SELECT course_id,MAX(score_number),MIN(score_number)
FROM t_score
GROUP BY course_id;
19、按各科平均成绩从低到高和及格率的百分数从高到低顺序
SELECT t_course.course_id AS 课程号,course_name AS 课程名,IFNULL(AVG(score_number),0) AS 平均成绩,
100*SUM(CASE WHEN IFNULL(score_number,0)>=60 THEN 1 ELSE 0 END)/COUNT(*) AS 及格百分数
FROM t_score,t_course
WHERE t_score.course_id=t_course.course_id
GROUP BY t_course.course_id
ORDER BY avg(score_number) ASC,100*SUM(CASE WHEN IFNULL(score_number,0)>=60 THEN 1 ELSE 0 END)/COUNT(*) DESC;
20、查询如下课程平均成绩和及格率的百分数(用”1行”显示): 语文(001),数学(002),外语 (003)
SELECT
SUM(CASE WHEN course_id=001 THEN score_number ELSE 0 END)/SUM(CASE WHEN course_id=001 THEN 1 ELSE 0 END) AS 语文平均分,
100*SUM(CASE WHEN course_id=001 AND score_number>=60 THEN 1 ELSE 0 END)/SUM(CASE WHEN course_id=001 THEN 1 ELSE 0 END) AS 语文及格百分比,
SUM(CASE WHEN course_id=002 THEN score_number ELSE 0 END)/SUM(CASE WHEN course_id=002 THEN 1 ELSE 0 END) AS 数学平均分,
100*SUM(CASE WHEN course_id=002 AND score_number>=60 THEN 1 ELSE 0 END)/SUM(CASE WHEN course_id=002 THEN 1 ELSE 0 END) AS 数学及格百分比,
SUM(CASE WHEN course_id=003 THEN score_number ELSE 0 END)/SUM(CASE WHEN course_id=003 THEN 1 ELSE 0 END) AS 外语平均分,
100*SUM(CASE WHEN course_id=003 AND score_number>=60 THEN 1 ELSE 0 END)/SUM(CASE WHEN course_id=003 THEN 1 ELSE 0 END) AS 外语及格百分比
FROM t_score;
SELECT
(SELECT SUM(score_number) FROM t_score WHERE course_id=001)/(SELECT count(course_id) FROM t_score WHERE course_id=001) AS 语文平均分,
100*(SELECT COUNT(*) FROM t_score WHERE course_id=001 AND score_number>=60)/(SELECT count(course_id) FROM t_score WHERE course_id=001) AS 语文及格百分比,
(SELECT SUM(score_number) FROM t_score WHERE course_id=002)/(SELECT count(course_id) FROM t_score WHERE course_id=002) AS 数学平均分,
100*(SELECT COUNT(*) FROM t_score WHERE course_id=002 AND score_number>=60)/(SELECT count(course_id) FROM t_score WHERE course_id=002) AS 数学及格百分比,
(SELECT SUM(score_number) FROM t_score WHERE course_id=003)/(SELECT count(course_id) FROM t_score WHERE course_id=003) AS 外语平均分,
100*(SELECT COUNT(*) FROM t_score WHERE course_id=003 AND score_number>=60)/(SELECT count(course_id) FROM t_score WHERE course_id=003) AS 外语及格百分比
;
21、查询不同老师所教不同课程平均分从高到低显示
SELECT teacher_name AS 教师姓名,t_teacher.teacher_id AS 教师ID,t_course.course_name AS 课程名称,t_course.course_id AS 课程ID,AVG(t_score.score_number) AS 平均成绩
FROM t_score,t_course,t_teacher
WHERE t_score.course_id=t_course.course_id AND t_course.teacher_id=t_teacher.teacher_id
GROUP BY t_teacher.teacher_id
ORDER BY AVG(t_score.score_number) DESC;
22、查询如下课程成绩第 3 名到第 6 名的学生成绩单:语文(001),数学(002),外语 (003),显示方式:[学生ID],[学生姓名],语文,外语,数学,平均成绩
SELECT DISTINCT
t_student.student_id AS 学生ID,
student_name AS 学生姓名,
T1.score_number AS 语文,
T2.score_number AS 数学,
T3.score_number AS 外语,
(IFNULL(T1.score_number,0)+IFNULL(T2.score_number,0)+IFNULL(T3.score_number,0))/3 AS 平均分
FROM t_student,t_score
LEFT JOIN t_score AS T1 ON t_score.student_id=T1.student_id AND T1.course_id=001
LEFT JOIN t_score AS T2 ON t_score.student_id=T2.student_id AND T2.course_id=002
LEFT JOIN t_score AS T3 ON t_score.student_id=T3.student_id AND T3.course_id=003
WHERE t_student.student_id=t_score.student_id
ORDER BY IFNULL(T1.score_number,0)+IFNULL(T2.score_number,0)+IFNULL(T3.score_number,0) DESC
LIMIT 2,4
;
LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1)
SELECT
*
FROM
table LIMIT 5,10; // 检索记录行 6-15
//为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
mysql>
SELECT
*
FROM
table LIMIT 95,-1; // 检索记录行 96-last.
//如果只给定一个参数,它表示返回最大的记录行数目:
mysql>
SELECT
*
FROM
table LIMIT 5; //检索前 5 个记录行
//换句话说,LIMIT n 等价于 LIMIT 0,n。
23、统计列印各科成绩,各分数段的人数:课程ID,课程名称,[100-85],[85-70],[70-60],[ <60]
SELECT t_score.course_id AS 课程ID, course_name AS 课程名称,
SUM(CASE WHEN score_number BETWEEN 85 AND 100 THEN 1 ELSE 0 END) AS `[100-85]`,
SUM(CASE WHEN score_number BETWEEN 70 AND 85 THEN 1 ELSE 0 END) AS `[85-70]`,
SUM(CASE WHEN score_number BETWEEN 60 AND 70 THEN 1 ELSE 0 END) AS `[70-60]`,
SUM(CASE WHEN score_number < 60 THEN 1 ELSE 0 END) AS `[<60]`
FROM t_score,t_course
WHERE t_score.course_id=t_course.course_id
GROUP BY t_score.course_id
;
24、查询学生平均成绩及其名次
SELECT a.student_id,a.num AS 平均成绩,COUNT(*) AS 名次
FROM
(SELECT t_score.student_id,AVG(t_score.score_number) AS num
FROM t_score
GROUP BY t_score.student_id) a,
(SELECT t_score.student_id,AVG(t_score.score_number) AS num
FROM t_score
GROUP BY t_score.student_id) b
WHERE a.num<=b.num
GROUP BY a.student_id
ORDER BY 名次 ASC
使用联接查询(笛卡尔积)
参考:https://blog.csdn.net/acmain_chm/article/details/4095531
25、查询每门课程分数最高的学生的姓名
SELECT course_name,student_name
FROM t_score,t_student,t_course
WHERE t_score.student_id=t_student.student_id AND t_score.course_id=t_course.course_id
AND score_number=(SELECT MAX(score_number) FROM t_score AS t_score2 WHERE t_score2.course_id=t_score.course_id)
26、查询各科成绩前三名的记录:(不考虑成绩并列情况)
比一条记录的成绩大的相同课程的数量小于3,那么他一定是这个课程的分数的前三名
SELECT student_id AS 学生ID,course_id AS 课程ID,score_number AS 分数
FROM t_score
WHERE(
SELECT count(*) FROM t_score AS t_score2 WHERE t_score2.course_id=t_score.course_id AND t_score2.score_number>t_score.score_number
)<3
ORDER BY course_id;
SELECT a.student_id AS 学生ID,a.course_id AS 课程ID,a.score_number AS 分数
FROM t_score a,t_score b
WHERE
a.course_id=b.course_id AND a.score_number<=b.score_number
GROUP BY a.score_id
HAVING COUNT(b.score_id)<=3
ORDER BY a.course_id
参考:https://blog.csdn.net/come_on_air/article/details/72902592
27、查询每门课程被选修的学生数
SELECT course_id,COUNT(course_id)
FROM t_score
GROUP BY course_id
28、查询出只选修了一门课程的全部学生的学号和姓名
SELECT t_student.student_id,student_name
FROM t_score,t_student
WHERE t_student.student_id=t_score.student_id
GROUP BY student_id
HAVING COUNT(course_id)=1
29、查询同名同性学生名单,并统计同名人数
SELECT student_name,COUNT(*)
FROM t_student
GROUP BY student_name
HAVING COUNT(*)>1
30、1981年出生的学生名单(注:Student表中Sage列的类型是datetime)
SELECT student_name,student_age
FROM t_student
WHERE (DATE_FORMAT(NOW(), '%Y')-student_age)=1981;
取当前的年份:DATE_FORMAT(NOW(), ‘%Y’)
31、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列
SELECT t_score.course_id,course_name,AVG(score_number) FROM t_score,t_course
GROUP BY t_score.course_id
ORDER BY AVG(score_number),t_score.course_id DESC
32、查询平均成绩大于85的所有学生的学号、姓名和平均成绩
SELECT t_score.student_id,student_name,AVG(score_number)
FROM t_score,t_student
WHERE t_score.student_id=t_student.student_id
GROUP BY t_score.student_id
HAVING AVG(score_number)>85
33 以上是关于SQL语句练习的主要内容,如果未能解决你的问题,请参考以下文章