版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
最好的学习方法就是保持感觉,要多练习,多敲代码,多思考,同一个问题有不同的解法
下面我们来实际操作
建立三个表
Student:学生表
字段:sid 学生id
sname 学生名字
sage 年龄
ssex 性别
create table `Student`(
sid varchar(10),
sname varchar(10),
sage datetime,
ssex nvarchar(10),
PRIMARY key (sid)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
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' , '女');
Course:课程表
字段:cid 课程id
cname 课程名称
tid 教师id
create table Course(
cid varchar(10),
cname varchar(10),
tid varchar(10),
PRIMARY key (cid)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
教师表:Teacher
字段:tid 教师id
tname:教师名字
create table Teacher(
tid varchar(10),
tname varchar(10),
PRIMARY key (tid)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
SC:分数表
字段:sid 学生id
cid:课程id
score:分数
create table SC(
sid varchar(10),
cid varchar(10),
score decimal(18,1),
key (sid)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;);
insert into SC values('01' , '01' , 80);
insert into SC values('01' , '02' , 90);
insert into SC values('01' , '03' , 99);
insert into SC values('02' , '01' , 70);
insert into SC values('02' , '02' , 60);
insert into SC values('02' , '03' , 80);
insert into SC values('03' , '01' , 80);
insert into SC values('03' , '02' , 80);
insert into SC values('03' , '03' , 80);
insert into SC values('04' , '01' , 50);
insert into SC values('04' , '02' , 30);
insert into SC values('04' , '03' , 20);
insert into SC values('05' , '01' , 76);
insert into SC values('05' , '02' , 87);
insert into SC values('06' , '01' , 31);
insert into SC values('06' , '03' , 34);
insert into SC values('07' , '02' , 89);
insert into SC values('07' , '03' , 98);
了解了表结构和字段定义,接下来进入正题
-- 查询"01"课程比"02"课程成绩高的学生的信息及课程分数
select a.*,b.score
from student as a
inner join sc as b on a.sid=b.sid
where a.sid in
(
SELECT a.sid
from sc as a left join sc as b on a.sid=b.sid and b.cid=02 -- 查询"01"课程比"02"课程成绩高的学生id
where a.cid=01
and a.score>b.score)
-- 第二题:1.1 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )
SELECT
*
FROM
( SELECT * FROM sc WHERE cid = 01 ) AS a -- 存在" 01 "课程
LEFT JOIN sc AS b ON a.sid = b.sid and b.cid = 02 -- 不存在" 02 "课程时显示为null
-- 1.2 查询同时存在01和02课程的情况
SELECT
*
FROM
( SELECT * FROM sc WHERE cid = 01 ) AS a -- 存在" 01 "课程
inner JOIN sc AS b ON a.sid = b.sid and b.cid = 02 -- 存在" 02 "课程
-- 1.3 查询选择了02课程但没有01课程的情况
SELECT
*
FROM
( SELECT * FROM sc WHERE cid = 02 ) AS a -- 存在" 02 "课程
left JOIN sc AS b ON a.sid = b.sid and b.cid = 01 -- 存在" 01 "课程
where b.sid is null
-- not in
SELECT
*
FROM
sc
WHERE
cid = 02
AND sid NOT IN ( SELECT sid FROM sc WHERE cid = 01 )
-- 2.查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
SELECT
a.sid,
a.sname,
b.avg
FROM
student AS a
INNER JOIN (
SELECT
sid,
round( avg( score ), 2 ) AS avg
FROM
sc
GROUP BY
sid
HAVING
avg( score ) >= 60
) AS b ON a.sid = b.sid
-- 查询所有同学的学生编号、学生姓名、选课总数、所有课程的成绩总和
select b.sid,b.sname,count(a.cid),sum(a.score)
from sc as a left join student as b on a.sid=b.sid
GROUP BY b.sid
-- 6.查询学过「张三」老师授课的同学的信息
-- 优先用连接
SELECT s.*
FROM student AS s INNER JOIN sc ON s.sid = sc.sid
INNER JOIN course AS c ON sc.cid = c.cid
INNER JOIN teacher AS t ON t.tid = c.tid
WHERE t.tname = '张三';
select *
from student
where
sid in
(
SELECT sid
FROM sc
where cid in (
select cid
from course
where tid in
(
select tid
from teacher
where tname='张三' )))
-- 查询没有学全所有课程的同学的信息
select a.*
from student as a
where a.sid not in (
select sid
from sc
group by sid
HAVING count(cid)>=(select count(distinct cid) from course)) #没有学全分为 学了一部分 和 完全没学,所以不可用 in <
SELECT s.*,COUNT(cid)
FROM sc RIGHT JOIN student AS s
ON sc.sid = s.sid
GROUP BY sc.sid
HAVING COUNT(cid) < (SELECT COUNT(DISTINCT cid)
FROM course);
-- 查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
select a.*
from student as a inner join sc as b on a.sid=b.sid and b.cid in (
select b.cid
from student as a right join sc as b on a.sid=b.sid
where a.sid=01)
where a.sid != 01
GROUP BY a.sid
-- 查询和" 01 "号的同学学习的课程完全相同的其他同学的信息
select a.*
from student as a inner join sc as b on a.sid=b.sid
where a.sid != 01
GROUP BY a.sid
having count(b.cid)=
(select count(cid)
from sc
where sid=01) -- 这里取了个巧,01号同学学了全部的课程,所以只要找可以找到学了全部课程(3科)的人就行
-- 查询和" 07 "号的同学学习的课程完全相同的其他同学的信息
SELECT
a.*
FROM
sc AS a
inner JOIN sc AS b ON a.sid=b.sid and b.sid=07
where a.sid!=07
-- 查询没学过"张三"老师讲授的任一门课程的学生姓名
select sid,sname
from student
where sid not in (
select sid
from sc as a
inner join course as b on a.cid=b.cid
inner join teacher as c on b.tid=c.tid and c.tname='张三')
-- 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
SELECT
a.sid,
a.sname,
avg(b.score)
FROM
student AS a inner join sc as b on a.sid=b.sid
WHERE
a.sid IN (
SELECT
aa.sid
FROM
( SELECT sid, count( 1 ) AS num_faill FROM sc WHERE score < 60 GROUP BY sid ) AS aa
WHERE
aa.num_faill >= 2
)
GROUP BY a.sid
-- GROUP BY having
SELECT
a.sid,
a.sname,
avg( b.score )
FROM
student AS a
INNER JOIN sc AS b ON a.sid = b.sid AND b.score < 60
GROUP BY a.sid
HAVING count( b.score ) >=2 -- 这个有点取巧了,4和6的所有分数都小于60
-- ,会全部选出,求的是全部课程的平均值,如果有一个人是2门小于60一门大于60,这里只会计算出小于60的两门分数平均
-- 检索" 01 "课程分数小于 60,按分数降序排列的学生信息
SELECT
a.*,
b.cid,
b.score
FROM
student AS a
INNER JOIN sc AS b ON a.sid = b.sid
AND b.score < 60
AND b.cid = 01
ORDER BY
b.score DESC
-- 按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
SELECT
aa.sid,
aa.score,
bb.avg_score
FROM
( SELECT sid, score FROM sc ) AS aa
INNER JOIN ( SELECT sid, avg( score ) AS avg_score FROM sc GROUP BY sid ) AS bb ON aa.sid = bb.sid
ORDER BY
bb.avg_score DESC
-- 查询各科成绩最高分、最低分和平均分,以如下形式显示:
-- 课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
-- 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
select
a.cid,
a.cname,
max(b.score),
min(b.score),
avg(b.score),
count(case when b.score>=60 then b.sid else null end )/count(b.cid),
count(case when b.score >=70 and b.score < 80 then b.sid else null end )/count(b.cid),
count(case when b.score >= 80 and b.score <90 then b.sid else null end )/count(b.cid),
count(case when b.score >= 90 then b.sid else null end )/count(b.sid)
from course as a inner join sc as b on a.cid=b.cid
GROUP BY b.cid
-- 按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺*************
SELECT
*,
COUNT( a.score ) AS rank
FROM
sc AS a
LEFT JOIN sc AS b ON a.cid = b.cid AND a.score < b.score
GROUP BY
a.cid,
a.sid
ORDER BY
a.cid,
rank;
-- 按各科成绩进行行排序,并显示排名, Score 重复时合并名次
SELECT
a.*,
COUNT(b.score)+1 AS rank
FROM
sc AS a
LEFT JOIN sc AS b
ON a.cid = b.cid
AND a.score < b.score
GROUP BY a.cid,
a.sid
ORDER BY a.cid,
rank ;
-- 查询学生的总成绩,并进行排名,总分重复时保留名次空缺************
SELECT
a.*,
@rank := @rank + 1 AS rank
FROM
( SELECT sid, SUM( score ) FROM sc GROUP BY sid ORDER BY SUM( score ) DESC ) a
INNER JOIN ( SELECT @rank := 0 ) b ON 1 = 1;
-- 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺***********************
SELECT
a.*,
CASE
WHEN @fscore = a.sumscore
THEN @rank
WHEN @fscore := a.sumscore
THEN @rank := @rank + 1
END AS rank
FROM
(SELECT
sc.sid,
SUM(score) AS sumscore
FROM
sc
GROUP BY sid
ORDER BY SUM(score) DESC) AS a,
(SELECT
@rank := 0,
@fscore := NULL) AS t ;
-- 统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
select a.cid,a.cname,
count( case when b.score >=85 and b.score<=100 then b.sid else null end)/count(sid),
sum( case when b.score >=85 and b.score<=100 then 1 else null end),
count( case when b.score >=70 and b.score<=85 then b.sid else null end)/count(sid),
sum( case when b.score >=70 and b.score<=85 then 1 else null end),
count( case when b.score >=60 and b.score<=70 then b.sid else null end)/count(sid),
sum( case when b.score >=60 and b.score<=70 then 1 else null end),
count( case when b.score >=0 and b.score<=60 then b.sid else null end)/count(sid),
sum( case when b.score >=0 and b.score<=60 then 1 else null end)
from course as a
inner join sc as b on a.cid=b.cid
GROUP BY cid
-- 查询各科成绩前三名的记录
SELECT a.*,b.*
-- COUNT(b.score) +1 AS ranking
FROM SC AS a LEFT JOIN SC AS b
ON a.cid = b.cid AND a.score<b.score
GROUP BY a.cid,a.sid
HAVING ranking <= 3
ORDER BY a.cid,ranking;
-- 查询出只选修两门课程的学生学号和姓名
SELECT
sid,
sname
FROM
student
WHERE
sid IN ( SELECT sid FROM sc GROUP BY sid HAVING count( cid ) = 2 )
-- 改为连接
SELECT
a.sid,
a.sname
FROM
student AS a
INNER JOIN sc AS b ON a.sid = b.sid
GROUP BY
a.sid
HAVING
count( b.cid ) =2
-- 查询男生、女生人数
SELECT
ssex,
count( sid )
FROM
student
GROUP BY
ssex
-- 用case when
SELECT
count( CASE WHEN ssex = '男' THEN sid ELSE NULL END ) AS '男',
count( CASE WHEN ssex = '女' THEN sid ELSE NULL END ) AS '女'
FROM
student
-- 查询同名且性别相同的学生名单,并统计同名人数**********************
select ssex,sname,count(sid)
from student
group by ssex,sname
having count(sid)>1
-- 查询 1990 年出生的学生名单
select *
from student
where sage like '1990%'
-- 结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
SELECT cid,avg(score)
from sc
GROUP BY cid
ORDER BY avg(score) desc,cid
-- 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
select a.sid,a.sname,avg(b.score)
from student as a inner join sc as b on a.sid=b.sid
GROUP BY b.sid
having avg(b.score)>=85
-- 查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
SELECT *
from sc as a inner join student as b on a.sid=b.sid inner join course c on a.cid=c.cid and c.cname='数学'
where a.score<60
-- 查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
SELECT
a.sname,
b.cid,
b.score
FROM
student as a
INNER JOIN sc AS b
ON a.sid = b.sid
AND b.score > 70 ;
-- 成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
SELECT
a.*,
b.score
FROM
student AS a
INNER JOIN sc AS b ON a.sid = b.sid
WHERE
b.cid IN ( SELECT cid FROM course WHERE tid IN ( SELECT tid FROM teacher WHERE tname = '张三' ) )
ORDER BY b.score desc
limit 1
-- 成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生
-- 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩*******************
select a.*,b.*
from sc as a inner join sc as b on a.score=b.score
where a.sid!=b.sid
-- 查询每门成绩最好的前两名**************
找到大于某个成绩只有两人就是前两名
SELECT
*
FROM
sc
WHERE
(SELECT
COUNT(*)
FROM
sc AS a
WHERE sc.cid = a.cid
AND sc.score < a.score) < 2
ORDER BY cid ASC,
sc.score DESC ;
-- 查询选修了全部课程的学生信息
select *
from student
where sid in(
select sid
from sc
group by sid
having count(cid)=( SELECT COUNT( * ) FROM course ))
-- 查询各学生的年龄,只按年份来算
SELECT
sid,
( YEAR ( CURDATE( ) ) - YEAR ( sage ) ) AS 'age'
FROM
student
-- 按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
SELECT
sid,
( case when CURDATE()<date(sage) then ( YEAR ( CURDATE( ) ) - YEAR ( sage )-1 ) else (YEAR ( CURDATE( ) ) - YEAR ( sage ) ) end ) AS 'age'
FROM
student
-- 查询本周过生日的学生
select sname
from student
where week(sage)=week(CURDATE())
-- 查询下周过生日的学生
SELECT
sname
FROM
student
WHERE WEEK(sage) = WEEK(NOW()) + 1