SQL实练
数据环境准备
数据表创建
create table Student(
SId varchar(10),
Sname varchar(10),
Sage datetime,
Ssex varchar(10)
);
create table Course(
CId varchar(10),
Cname nvarchar(10),
TId varchar(10)
);
create table Teacher(
TId varchar(10),
Tname varchar(10)
);
create table SC(
SId varchar(10),
CId varchar(10),
score decimal(18,1)
);
数据初始化
-- 学生表 Student
-- 学生表 Student
insert into Student values('01' , '赵雷' , '1990-01-01' , '男');
insert into Student values('02' , '钱电' , '1990-12-21' , '男');
insert into Student values('03' , '孙风' , '1990-12-20' , '男');
insert into Student values('04' , '李云' , '1990-12-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吴兰' , '1992-01-01' , '女');
insert into Student values('07' , '郑竹' , '1989-01-01' , '女');
insert into Student values('09' , '张三' , '2017-12-20' , '女');
insert into Student values('10' , '李四' , '2017-12-25' , '女');
insert into Student values('11' , '李四' , '2012-06-06' , '女');
insert into Student values('12' , '赵六' , '2013-06-13' , '女');
insert into Student values('13' , '孙七' , '2014-06-01' , '女');
-- 课程表 Course
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
-- 教师表 Teacher
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
-- 成绩表 SC
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);
练习题
常规题
1.查询" 01 “课程比” 02 "课程成绩高的学生的信息及课程分数
select sc.sid, sc.score
from SC sc
where sc.cid = '01';
select sc.sid, sc.score
from SC sc
where sc.cid = '02';
SELECT t1.SId,
t1.CId,
t1.score as '语文',
t2.score as '数学'
FROM (SELECT SId,
CId,
score
FROM SC
WHERE CId = '01') t1
LEFT JOIN
(SELECT SId,
CId,
score
FROM SC
WHERE CId = '02') t2
ON t1.SId = t2.SId
WHERE t1.score > t2.score;
SELECT tt1.SId
, tt2.Sname
, tt3.CId
, tt3.score
FROM (SELECT t1.SId
FROM (SELECT SId
, CId
, score
FROM SC
where CId = '01') t1
LEFT JOIN(SELECT SId
, CId
, score
FROM SC
WHERE CId = '02') t2
ON t1.SId = t2.SId
WHERE t1.Score > t2.Score) tt1
JOIN Student tt2 ON tt1.SId = tt2.SId
JOIN SC tt3 ON tt1.SId = tt3.SId;
2.查询同时存在" 01 “课程和” 02 "课程的情况
select sc.sid, sc.score
from SC sc
where sc.cid = '01';
select sc.sid, sc.score
from SC sc
where sc.cid = '02';
SELECT t1.SId
FROM (SELECT SId
FROM SC
WHERE CId = '01') AS t1
JOIN (SELECT SId
FROM SC
WHERE CId = '02') AS t2
ON t1.SId = t2.SId;
3.查询存在" 01 “课程但可能不存在” 02 "课程的情况(不存在时显示为 null )
-- 左连接
SELECT t1.SId
, t1.CId
, t1.score
, t2.CId AS t2CId
, t2.score AS t2Score
FROM (SELECT SId
, CId
, score
FROM SC
WHERE CId =
LEFT JOIN(SELECT SId
, CId
, score
FROM SC
WHERE CId =
ON t1.SId = t2.SId;
4.查询不存在" 01 “课程但存在” 02 "课程的情况
-- 右连接
SELECT t1.SId
, t1.CId
, t1.score
, t2.CId AS t2CId
, t2.score AS t2Score
FROM (SELECT SId
, CId
, score
FROM SC
WHERE CId =
RIGHT JOIN(SELECT SId
, CId
, score
FROM SC
WHERE CId =
ON t1.SId = t2.SId;
5.查询平均成绩于大于 60 分的同学的学生编号和学生姓名和平均成绩
select sc.sid, round(avg(sc.score), 2) as avgScore
from SC sc
group by sc.sid
having round(avg(sc.score), 2) > 60;
select tt.sid, s.sname, tt.avgScore
from (select sc.sid, round(avg(sc.score), 2) as avgScore
from SC sc
group by sc.sid
having round(avg(sc.score), 2) > 60) tt
join Student s on tt.SId=s.SId
6.查询在 SC 表存在成绩的学生信息
select distinct sc.sid
from SC sc;
select s.*
from Student s
where s.SId in (select distinct sc.sid from SC sc)
7.查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩,没成绩的显示为 null
-- 按照sid分组统计选课总数
select sc.sid, count(1) as courseNum
from SC sc
group by sc.sid;
-- 按照sid分组统计总成绩
select sc.sid, SUM(sc.score) as SumScore
from SC sc
group by sc.sid;
-- 上述2个可以一起查询
select sc.sid, count(1) as courseNum, SUM(sc.score) as SumScore
from SC sc
group by sc.sid;
-- 联合学生表信息查询
select s.sid, s.sname, t1.courseNum, t1.SumScore
from Student s
left join (select sc.sid, count(1) as courseNum, SUM(sc.score) as SumScore
from SC sc
group by sc.sid) t1 on s.sid = t1.SId;
8.查询「李」姓老师的数量
select count(1) from Teacher t where t.Tname like '李%'
9.查询学过「张三」老师授课的同学的信息
select t.TId
from Teacher t
where t.Tname = '张三';
select c.CId
from Course c
where c.TId = (select t.TId from Teacher t where t.Tname = '张三');
select distinct sc.sid
from SC sc
where sc.CId in (select c.CId from Course c where c.TId = (select t.TId from Teacher t where t.Tname = '张三'));
select s.*
from Student s
where s.SId in (select distinct sc.sid
from SC sc
where sc.CId in
(select c.CId from Course c where c.TId = (select t.TId from Teacher t where t.Tname = '张三')));
select s.*
from Student s
join(select distinct sc.sid
from SC sc
where sc.CId in
(select c.CId from Course c where c.TId = (select t.TId from Teacher t where t.Tname = '张三'))) t1
on s.SId = t1.SId;
10.查询没有学全所有课程的同学的信息
-- 1.按照学生sid分组统计课程数量
select sc.sid, count(1) as courseNum
from SC sc
group by sc.sid;
-- 统计所有课程数量
select count(1) as totalCourseNum
from Course;
-- 联合学生信息
select s.*, t1.courseNum
from Student s
left join (select sc.sid, count(1) as courseNum from SC sc group by sc.sid) t1
on s.SId = t1.SId
where t1.courseNum<3 ||t1.courseNum is null;
11.查询至少有一门课与学号为" 01 "的同学所学相同的同学的信息
select sc.CId
from SC sc
where sc.SId = '01';
select distinct sc.sid
from SC sc
where sc.CId in (select sc.CId from SC sc where sc.SId = '01')
and sc.SId != '01';
select *
from Student s
where s.SId in (select distinct sc.sid
from SC sc
where sc.CId in (select sc.CId from SC sc where sc.SId = '01')
and sc.SId != '01');
12.查询和" 01 "号的同学学习的课程 完全相同的其他同学的信息
select sc.CId
from SC sc
where sc.SId = '01';
SELECT SId,
CId
FROM SC
WHERE SId != '01';
select sc.sid, count(1) as courseNumCount
from SC sc
group by sc.sid
having (count(1)) = (select count(1)
from SC sc
where sc.SId = '01');
select distinct t1.SId
from (select sc.sid, count(1) as courseNumCount
from SC sc
group by sc.sid
having (count(1)) = (select count(1)
from SC sc
where sc.SId = '01')) t1
join(select sc.sid
from SC sc
where sc.SId != '01'
and sc.CId in (select sc.CId
from SC sc
where sc.SId = '01')) t2 on t1.SId=t2.SId;
select s.* from Student s join (select distinct t1.SId
from (select sc.sid, count(1) as courseNumCount
from SC sc
group by sc.sid
having (count(1)) = (select count(1)
from SC sc
where sc.SId = '01')) t1
join(select sc.sid
from SC sc
where sc.SId != '01'
and sc.CId in (select sc.CId
from SC sc
where sc.SId = '01')) t2 on t1.SId=t2.SId) tt on s.SId=tt.SId;
13.查询没学过"张三"老师讲授的任一门课程的学生姓名
-- 1.查询张三老师教的课程
select c.CId
from Course c
where c.TId = (select t.TId from Teacher t where t.Tname = '张三');
select group_concat('%', c.cid, '%')
from Course c
where c.TId = (select t.TId from Teacher t where t.Tname = '张三');
-- 查询学生课程信息
select sc.SId, group_concat(sc.CId order by sc.CId asc)
from SC sc
group by sc.SId;
select s.SId, s.Sname, t1.CId
from Student s
left join (select sc.SId, group_concat(sc.CId order by sc.CId asc) as cid
from SC sc
group by sc.SId) t1 on s.SId = t1.SId;
-- 拼接条件:没学过"张三"老师讲授的任一门课程
select s.SId, s.Sname, t1.CId
from Student s
left join (select sc.SId, group_concat(sc.CId order by sc.CId asc) as cid from SC sc group by sc.SId) t1
on s.SId = t1.SId
where t1.CId not like (select group_concat('%', c.cid, '%')
from Course c
where c.TId = (select t.TId from Teacher t where t.Tname = '张三'))
or t1.cid is null;
14.查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
select *
from SC sc
where sc.score < 60;
select sc.sid, count(1) as courseNum, avg(sc.score)
from (select * from SC sc where sc.score < 60) sc
group by sc.sid
having (count(1)) >= 2;
select s.SId, s.Sname, t1.avgScore
from Student s
join (select sc.sid, count(1) as courseNum, avg(sc.score) as avgScore
from (select * from SC sc where sc.score < 60) sc
group by sc.sid
having (count(1)) >= 2) t1
on s.SId = t1.SId;
15.检索" 01 "课程分数小于 60,按分数降序排列的学生信息
select *
from SC sc
where sc.CId = '01'
and sc.score < 60;
SELECT t2.SId
,t2.Sname
,t1.score
FROM
SC t1 JOIN Student t2
ON t1.SId = t2.SId
AND t1.CId = '01' AND t1.score < 60
ORDER BY t1.score DESC;
16.按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
-- 查询平均成绩
select sc.SId, avg(sc.score) as avgScore
from SC sc
group by sc.SId;
-- 查询语文成绩:课程编号01
select sc.sid, sc.score as '语文成绩'
from SC sc
where sc.CId = '01';
-- 查询数学成绩:课程编号02
select sc.sid, sc.score as '数学成绩'
from SC sc
where sc.CId = '02';
-- 查询英语成绩:课程编号03
select sc.sid, sc.score as '英语成绩'
from SC sc
where sc.CId = '03';
-- 联合以上表查询
select tt1.sid, tt1.avgScore, tt2.语文成绩, tt3.数学成绩, tt4.英语成绩
from (select sc.SId, avg(sc.score) as avgScore from SC sc group by sc.SId) tt1
left join (select sc.sid
, sc.score as '语文成绩'
from SC sc
where sc.CId = '01') tt2
on tt1.sid = tt2.sid
left join (select sc.sid, sc.score as '数学成绩' from SC sc where sc.CId = '01') tt3 on tt1.sid = tt3.sid
left join (select sc.sid, sc.score as '英语成绩' from SC sc where sc.CId = '03') tt4 on tt1.sid = tt4.sid
order by tt1.avgScore desc;
-- with as 临时表改写
with tt as (select tt1.sid, tt1.avgScore, tt2.语文成绩, tt3.数学成绩, tt4.英语成绩
from (select sc.SId, avg(sc.score) as avgScore from SC sc group by sc.SId) tt1
left join (select sc.sid
, sc.score as '语文成绩'
from SC sc
where sc.CId = '01') tt2
on tt1.sid = tt2.sid
left join (select sc.sid, sc.score as '数学成绩' from SC sc where sc.CId = '01') tt3
on tt1.sid = tt3.sid
left join (select sc.sid, sc.score as '英语成绩' from SC sc where sc.CId = '03') tt4
on tt1.sid = tt4.sid)
select tt.sid, tt.avgScore, tt.语文成绩, tt.数学成绩, tt.英语成绩 from tt order by tt.avgScore desc;
17.查询各科成绩最高分、最低分和平均分: 以如下形式显示:课程 ID,课程 name,最分,最低分,平均分,及格率,中等率,优良率,优秀率 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
-- 17.查询各科成绩最高分、最低分和平均分:
-- 以如下形式显示:课程 ID,课程 name,最高分,最低分,平均分,及格率,中等率,优良率,优秀率
-- 及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
-- 要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
-- 1.最高分、最低分、平均分查询
select sc.CId,
MAX(sc.score) as maxScore,
MIN(sc.score) as minScore,
round(avg(sc.score), 2) as avgScore
from SC sc
group by sc.CId;
-- 2.及格率,中等率,优良率,优秀率
select sc.CId,
concat(round((select count(1) from SC t1 where sc.CId = t1.CId and t1.score >= 60) /
(select count(1) from SC t1 where sc.CId = t1.CId), 4) * 100, '%') as '及格率',
concat(round((select count(1) from SC t1 where sc.CId = t1.CId and t1.score >= 70 and t1.score <= 80) /
(select count(1) from SC t1 where sc.CId = t1.CId), 4) * 100, '%') as '中等率',
concat(round((select count(1) from SC t1 where sc.CId = t1.CId and t1.score >= 80 and t1.score <= 90) /
(select count(1) from SC t1 where sc.CId = t1.CId), 4) * 100, '%') as '优良率',
concat(round((select count(1) from SC t1 where sc.CId = t1.CId and t1.score >= 90) /
(select count(1) from SC t1 where sc.CId = t1.CId), 4) * 100, '%') as '优秀率'
from SC sc
group by sc.CId;
-- 3.课程编号和选课人数
select sc.CId,
count(1) as '选课人数'
from SC sc
group by sc.CId;
-- 联合以上表
select t1.cid as '课程 ID',
(case
when t1.CId = '01' then '语文'
when t1.CId = '02' then '数学'
when t1.CId = '03' then '英语'
else ''
end) as '课程名称',
t1.maxScore as '最高分',
t1.minScore as '最低分',
t1.avgScore as '平均分',
t2.及格率,
t2.中等率,
t2.优良率,
t2.优秀率,
t3.选课人数
from (select sc.CId as cid,
MAX(sc.score) as maxScore,
MIN(sc.score) as minScore,
round(avg(sc.score), 2) as avgScore
from SC sc
group by sc.CId) t1
join (select sc.CId,
concat(round((select count(1) from SC t1 where sc.CId = t1.CId and t1.score >= 60) /
(select count(1) from SC t1 where sc.CId = t1.CId), 4) * 100, '%') as '及格率',
concat(round((select count(1)
from SC t1
where sc.CId = t1.CId
and t1.score >= 70
and t1.score <= 80) /
(select count(1) from SC t1 where sc.CId = t1.CId), 4) * 100, '%') as '中等率',
concat(round((select count(1)
from SC t1
where sc.CId = t1.CId
and t1.score >= 80
and t1.score <= 90) /
(select count(1) from SC t1 where sc.CId = t1.CId), 4) * 100, '%') as '优良率',
concat(round((select count(1) from SC t1 where sc.CId = t1.CId and t1.score >= 90) /
(select count(1) from SC t1 where sc.CId = t1.CId), 4) * 100, '%') as '优秀率'
from SC sc
group by sc.CId) t2 on t1.cid = t2.CId
join (select sc.CId,
count(1) as '选课人数'
from SC sc
group by sc.CId) t3 on t1.cid = t3.CId
order by t3.选课人数 desc, t1.cid asc;
18.按各科平均成绩进行排序,并显示排名
select sc.cid,
round(avg(sc.score), 2) as avgScore
from SC sc
group by sc.cid
order by avgScore desc;
set @i := 0;
select t1.CId,
t1.avgScore as '平均成绩',
@i := @i + 1 as '排名'
from (select sc.cid,
round(avg(sc.score), 2) as avgScore
from SC sc
group by sc.cid
order by avgScore desc) t1
20.查询学生的总成绩,并进行排名
select sc.SId, SUM(sc.score) as totalScore
from SC sc
group by sc.SId;
select rank() over (order by t1.totalScore desc) as '排名',
t1.SId,
t1.totalScore as '总成绩'
from (select sc.SId, SUM(sc.score) as totalScore
from SC sc
group by sc.SId) t1;
select dense_rank() over (order by t1.totalScore desc) as '排名',
t1.SId,
t1.totalScore as '总成绩'
from (select sc.SId, SUM(sc.score) as totalScore
from SC sc
group by sc.SId) t1;
22.统计各科成绩各分数段人数:课程编号,课程名称,[100-85),[85-70),[70-60),[60-0)及所占百分
-- 22.统计各科成绩各分数段人数:课程编号,课程名称,[100-85),[85-70),[70-60),[60-0)及所占百分
-- 1.统计各科各分数段人数
select sc.CId,
concat(round((select count(1) from SC t1 where t1.CId = sc.CId and t1.score > 85 and t1.score <= 100) /
(select count(1) from SC t2 where t2.CId = sc.CId), 4) * 100, '%') as '[100-85)',
concat(round((select count(1) from SC t1 where t1.CId = sc.CId and t1.score > 70 and t1.score <= 85) /
(select count(1) from SC t2 where t2.CId = sc.CId), 4) * 100, '%') as '[85-70)',
concat(round((select count(1) from SC t1 where t1.CId = sc.CId and t1.score > 60 and t1.score <= 70) /
(select count(1) from SC t2 where t2.CId = sc.CId), 4) * 100, '%') as '[70-60)',
concat(round((select count(1) from SC t1 where t1.CId = sc.CId and t1.score > 0 and t1.score <= 60) /
(select count(1) from SC t2 where t2.CId = sc.CId), 4) * 100, '%') as '[60-0)'
from SC sc
group by sc.CId;
-- 关联上述查询结果
select t1.CId,
(case
when t1.CId = '01' then '语文'
when t1.CId = '02' then '数学'
when t1.CId = '03' then '英语'
else ''
end) as '课程名称',
t1.`[100-85)`,
t1.`[85-70)`,
t1.`[70-60)`,
t1.`[60-0)`
from (select sc.CId,
concat(round((select count(1) from SC t1 where t1.CId = sc.CId and t1.score > 85 and t1.score <= 100) /
(select count(1) from SC t2 where t2.CId = sc.CId), 4) * 100, '%') as '[100-85)',
concat(round((select count(1) from SC t1 where t1.CId = sc.CId and t1.score > 70 and t1.score <= 85) /
(select count(1) from SC t2 where t2.CId = sc.CId), 4) * 100, '%') as '[85-70)',
concat(round((select count(1) from SC t1 where t1.CId = sc.CId and t1.score > 60 and t1.score <= 70) /
(select count(1) from SC t2 where t2.CId = sc.CId), 4) * 100, '%') as '[70-60)',
concat(round((select count(1) from SC t1 where t1.CId = sc.CId and t1.score > 0 and t1.score <= 60) /
(select count(1) from SC t2 where t2.CId = sc.CId), 4) * 100, '%') as '[60-0)'
from SC sc
group by sc.CId) t1;
23.查询各科成绩前三名的记录
select
sc.CId,
sc.score
from SC sc
order by sc.CId asc,sc.score desc;
select
row_number() over (partition by t1.CId order by t1.score desc) as rn,
t1.sid,
t1.sname,
t1.CId,
t1.score
from (select
sc.SId as sid,
(select s.Sname from Student s where s.SId=sc.SId) as sname,
sc.CId,
sc.score
from SC sc
order by sc.CId asc,sc.score desc) t1;
select * from (select
row_number() over (partition by t1.CId order by t1.score desc) as rn,
t1.sid,
t1.sname,
t1.CId,
t1.score
from (select
sc.SId as sid,
(select s.Sname from Student s where s.SId=sc.SId) as sname,
sc.CId,
sc.score
from SC sc
order by sc.CId asc,sc.score desc) t1) t2
where t2.rn<=3;
24.查询每门课程被选修的学生数
select sc.CId, count(1) as '选课人数'
from SC sc
group by sc.CId;
25.查询出只选修两门课程的学生学号和姓名
select sc.SId, count(1) as '学生选课数量'
from SC sc
group by sc.SId;
select sc.SId, count(1) as '学生选课数量'
from SC sc
group by sc.SId
having count(1)=2;
select s.SId,Sname from Student s
join (select sc.SId, count(1) as '学生选课数量'
from SC sc
group by sc.SId
having count(1)=2) t on s.SId=t.SId;
26.查询男生、女生人数
select s.Ssex, count(1) as '性别人数'
from Student s
group by s.Ssex;
28.查询同名同性学生名单,并统计同名同性人数
select s.Sname, Ssex, count(1)
from Student s
group by s.Sname, Ssex
having count(1) > 1;
29.查询 1990 年出生的学生名单
select *
from Student s
where s.Sage like '1990%';
select *
from Student s
where s.Sage between '1990-01-01' and '1990-12-31';
30.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
select sc.CId, avg(sc.score)
from SC sc
group by sc.CId;
select sc.CId, avg(sc.score)
from SC sc
group by sc.CId
order by avg(sc.score) desc, sc.CId asc;
31.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
select sc.SId, avg(sc.score)
from SC sc
group by sc.SId;
select sc.SId, avg(sc.score)
from SC sc
group by sc.SId
having avg(sc.score) >= 85;
select s.SId,Sname,t.avgScore as '平均成绩'
from Student s
join(select sc.SId, avg(sc.score) as avgScore
from SC sc
group by sc.SId
having avg(sc.score) >= 85) t on s.SId = t.SId;
32.查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
select sc.*
from SC sc
where sc.score < 60;
select c.CId
from Course c
where c.Cname = '数学';
select sc.SId, sc.score
from SC sc
join (select c.CId from Course c where c.Cname = '数学') t on sc.CId = t.CId
where sc.score < 60;
select s.SId, Sname, tt.score
from Student s
join(select sc.SId, sc.score
from SC sc
join (select c.CId from Course c where c.Cname = '数学') t on sc.CId = t.CId
where sc.score < 60) tt
on s.SId = tt.SId
33.查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
SELECT SId,
SUM(CASE CId WHEN '01' THEN score ELSE 0 END) AS '语文成绩',
SUM(CASE CId WHEN '02' THEN score ELSE 0 END) AS '数学成绩',
SUM(CASE CId WHEN '03' THEN score ELSE 0 END) AS '英语成绩'
FROM SC
GROUP BY SId;
select SId,
SUM(if(cid = '01', score, 0)) as '语文成绩',
SUM(if(cid = '02', score, 0)) as '数学成绩',
SUM(if(cid = '03', score, 0)) as '英语成绩'
from SC
GROUP BY SId;
select s.SId,
s.Sname,
t.语文成绩 as '语文成绩',
t.数学成绩 as '数学成绩',
t.英语成绩 as '英语成绩'
from Student s
left join (select SId,
SUM(if(cid = '01', score, 0)) as '语文成绩',
SUM(if(cid = '02', score, 0)) as '数学成绩',
SUM(if(cid = '03', score, 0)) as '英语成绩'
from SC
GROUP BY SId) t on s.SId = t.SId;
select
tt.SId,
tt.Sname,
if(tt.语文成绩 is null ,0,tt.语文成绩) as '语文成绩',
if(tt.数学成绩 is null ,0,tt.数学成绩) as '数学成绩',
if(tt.英语成绩 is null ,0,tt.英语成绩) as '英语成绩'
from (select s.SId,
s.Sname,
t.语文成绩 as '语文成绩',
t.数学成绩 as '数学成绩',
t.英语成绩 as '英语成绩'
from Student s
left join (select SId,
SUM(if(cid = '01', score, 0)) as '语文成绩',
SUM(if(cid = '02', score, 0)) as '数学成绩',
SUM(if(cid = '03', score, 0)) as '英语成绩'
from SC
GROUP BY SId) t on s.SId = t.SId) tt;
三种常见的排名
ROW_NUMBER:可以做为序号
set @i := 0;
SELECT t1.SId,
t1.CId,
t1.score,
@i := @i + 1 as '排名'
from (
SELECT
SId, CId, score
from SC
order by score desc
) t1;
select row_number() over (order by t1.score desc) as '排名',
t1.SId,
t1.CId,
t1.score
from SC t1
DENSE_RANK
-- 1 2 3 3 3 4 5 6 7 有重复时并列排名,最终排名也是连续的
-- MySQL 5.7
SET @i := 0;
SET @p := 0;
SET @q := 0;
SELECT t1.SId,
t1.CId,
t1.score,
@p := t1.score,
if(@p = @q, @i, @i := @i + 1) as '排名',
@q :=@p
from (
SELECT SId,
CId,
score
from SC
order by score desc
) t1;
-- mysql 8.0以上
-- dense_rank()函数
select dense_rank() over (order by t1.score desc) as '排名',
t1.SId,
t1.CId,
t1.score
from SC t1;
RANK
-- 1 2 3 3 3 6 7 8 有重复时并列排名,最终排名不连续
-- MySQL 5.7
SET @i := 0;
SET @j := 0;
SET @p := 0;
SET @q := 0;
SELECT
t1.SId,
t1.CId,
t1.score,
@j := @j + 1,
@p := t1.score,
if(@p=@q,@i,@i := @j) as '排名',
@q :=@p
from (
SELECT SId
,CId
,score
from SC
order by score desc
) t1;
-- mysql 8.0以上
-- rank()函数
select rank() over (order by t1.score desc) as '排名',
t1.SId,
t1.CId,
t1.score
from SC t1;
sql查询常用函数
GROUP_CONCAT 拼接函数
-- 查询学生选课情况,课程编号升序,按照逗号拼接
select sc.SId, group_concat(sc.CId order by sc.CId asc) as cid
from SC sc
group by sc.SId
ifnull函数和Case when函数
-- ifnull函数,可以接收两个参数,如果第一个参数不为null,则返回第一个参数,否则返回第二个参数。
select s.SId as '学生编号',
s.Sname as '学生姓名',
(case
when S2.cid = '01' then '语文'
when S2.cid = '02' then '数学'
when S2.cid = '03' then '英语'
else ''
end) as '课程名称',
ifnull(S2.score, '缺考')
from Student s
left join SC S2 on s.SId = S2.SId
with as 临时表使用
-- with as临时表用法
-- 如下使用with as改写
select s.SId, s.Sname, t1.avgScore
from Student s
join (select sc.sid, count(1) as courseNum, avg(sc.score) as avgScore
from (select * from SC sc where sc.score < 60) sc
group by sc.sid
having (count(1)) >= 2) t1
on s.SId = t1.SId;
with t1 as (select sc.sid, count(1) as courseNum, avg(sc.score) as avgScore
from (select * from SC sc where sc.score < 60) sc
group by sc.sid
having (count(1)) >= 2)
select s.SId, s.Sname, t1.avgScore
from Student s join t1 on s.SId = t1.SId;
存储过程
drop table if exists `mystudy`.`t_model`;
Create table `mystudy`.`t_model`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`uid` bigint COMMENT '业务主键',
`modelid` varchar(50) COMMENT '字符主键',
`modelname` varchar(50) COMMENT '名称',
`desc` varchar(50) COMMENT '描述',
primary key (`id`),
UNIQUE index `uid_unique` (`uid`),
key `modelid_index` (`modelid`) USING BTREE
) ENGINE = InnoDB
charset = utf8
collate = utf8_bin;
create procedure xunhuancharu()
begin
DECLARE i INT DEFAULT 1;
WHILE (i <= 10)
DO
insert into t_model (uid,modelid,modelname,`desc`) value (i,CONCAT('id20170831',i),CONCAT('name',i),'desc');
SET i = i + 1;
END WHILE;
end;
call xunhuancharu();
drop procedure xunhuancharu;
SQL调优实战
数据环境准备
CREATE TABLE `employees` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
`position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',
`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',
PRIMARY KEY (`id`),
KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='员工记录表';
INSERT INTO employees(name,age,position,hire_time) VALUES('itwxe',22,'manager',NOW());
INSERT INTO employees(name,age,position,hire_time) VALUES('weiwei', 23,'test',NOW());
INSERT INTO employees(name,age,position,hire_time) VALUES('leilei',23,'dev',NOW());
drop procedure if exists insert_employees;
delimiter $$
create procedure insert_employees()
begin
declare i int;
set i = 1;
while(i <= 100000)do
insert into employees(name, age, position) values(CONCAT('itwxe', i), rand() * 42 + 18, 'dev');
set i = i + 1;
end while;
end$$
delimiter ;
call insert_employees();
1. 尽量全值匹配
explain select * from employees where name = 'itwxe';
explain select * from employees where name = 'itwxe' and age = 22;
explain select * from employees where name = 'itwxe' and age = 22 and position = 'manager';
2. 最左前缀原则
explain select * from employees where name = 'itwxe' and age = '18';
explain select * from employees where name = 'itwxe' and position = 'manager';
explain select * from employees where position = 'manager';
3. 不在索引列上做任何操作(计算、函数、(自动/手动)类型转换),会导致索引失效而转向全表扫描
-- 需要注意的是这里说的索引列任何操作(计算、函数、(自动/手动)类型转换)不做操作指的是 where 条件之后的,而不是查询结果字段里面的。
-- 不对where条件后的索引列做任何操作,使用索引
explain select * from employees where name = 'weiwei';
-- 对where条件后的索引列做left操作,索引失效
explain select * from employees where left(name,6) = 'weiwei';
4. 存储引擎不能使用索引中范围条件右边的列
explain select * from employees where name = 'itwxe' and age = 22 and position = 'manager';
explain select * from employees where name = 'itwxe' and age > 22 and position = 'manager';
5. 尽量使用覆盖索引,减少select *语句
-- 尽量使用覆盖索引,即只访问索引列,减少不必要的select *语句。
-- 如果结果只需要name,age字段,则只查询这2个,避免使用select *语句
explain select name,age from employees where name = 'itwxe' and age = '18';
6. MySQL 在使用不等于( != 或者 <> ),not in,not exists 的时候无法使用索引会导致全表扫描
-- 使用不等于( != 或者 <> ),not in,not exists 的时候,索引失效
explain select * from employees where name != 'itwxe';
explain select * from employees where name not in('itwxe');
7. is null 和 is not null 一般情况下也无法使用索引
-- is null 和 is not null 一般情况下也会导致索引失效
explain select * from employees where name is null;
explain select * from employees where name is not null;
8. like 以通配符开头(’%itwxe…’) MySQL 索引失效会变成全表扫描操作
explain select * from employees where name like 'wei%';
explain select * from employees where name like '%wei';
9. 类型不匹配 MySQL 自动转型导致索引失效(隐式类型转换)
10. 少用 or 或 in ,用它查询时,MySQL 不一定使用索引
索引使用总结
