建表语句
#########创建学生表
create table t_student(
sid int primary key,
sname varchar(10),
sage date,
ssex char(10)
)charset=utf8;
INSERT INTO t_student VALUES(01,'赵雷','1990-01-01','男');
INSERT INTO t_student VALUES(02,'钱电','1990-12-21','男');
INSERT INTO t_student VALUES(03,'孙凤','1990-05-20','男');
INSERT INTO t_student VALUES(04,'李云','1990-08-16','男');
INSERT INTO t_student VALUES(05,'周梅','1991-12-01','女');
INSERT INTO t_student VALUES(06,'吴兰','1992-03-01','女');
INSERT INTO t_student VALUES(07,'郑竹','1989-07-01','女');
INSERT INTO t_student VALUES(08,'王菊','1990-01-20','女');
#########创建课程表
create table t_course(
cou_id int primary key,
cou_name VARCHAR(10),
tea_id int
)charset=utf8;
insert into t_course values(01,'语文',02);
insert into t_course values(02,'数学',01);
insert into t_course values(03,'英语',03);
#########创建教师表
create table t_teacher(
tea_id int primary key,
tea_name VARCHAR(10)
)charset=utf8;
insert into t_teacher VALUES(01,'张三');
insert into t_teacher VALUES(02,'李四');
insert into t_teacher VALUES(03,'王五');
#########创建成绩表
create table t_grade(
stu_id int ,
cou_id int,
score int
)charset=utf8;
insert into t_grade values(01,01,80);
insert into t_grade values(01,02,90);
insert into t_grade values(01,03,99);
insert into t_grade values(02,01,70);
insert into t_grade values(02,02,60);
insert into t_grade values(02,03,80);
insert into t_grade values(03,01,80);
insert into t_grade values(03,02,80);
insert into t_grade values(03,03,80);
insert into t_grade values(04,01,50);
insert into t_grade values(04,02,30);
insert into t_grade values(04,03,20);
insert into t_grade values(05,01,76);
insert into t_grade values(05,02,87);
insert into t_grade values(06,01,31);
insert into t_grade values(06,02,34);
insert into t_grade values(07,01,89);
insert into t_grade values(07,03,98);
insert into t_grade values(08,02,100);
select * from t_student;
select * from t_course;
select * from t_teacher;
select * from t_grade;
查询开始
2019-05-19
#1. 查询" 01 "课程比" 02 "课程成绩高的学生的id及课程分数
方法1:
select a.*,b.cou_id,b.score from (select * from t_grade where cou_id=1)a
inner join (select * from t_grade where cou_id=2)b
on a.stu_id=b.stu_id
where a.score>b.score;
#总结:
#一张表的同一个字段进行比较,则必须先对原始表进行查询形成两张子表,两张子表join后再对该字段比较
方法2:
select a.*,b.cou_id,b.score from t_grade a
inner join t_grade b
on a.stu_id=b.stu_id and a.cou_id=1 and b.cou_id=2
where a.score>b.score;
#总结:
#由于子查询性能低于连接查询,方法2比方法1好,之后的习题尽量避免子查询,使用连接查询
##多重join的话,带where条件的join应该放在最后。
方法3:
select a.*,b.cou_id,b.score from t_grade a
inner join t_grade b
on a.stu_id=b.stu_id
where a.score>b.score and a.cou_id=1 and b.cou_id=2;
#总结:
#SQL92语法可将SQL99的连接条件全部移入where子句中,不过还是建议使用SQL99
#2.查询" 01 "课程比" 02 "课程成绩高的学生的详细信息及课程分数
select c.*,a.score 科目1分数,b.score 科目2分数 from t_student c
inner join t_grade a
on a.stu_id=c.sid and a.cou_id=1
inner join t_grade b
on b.stu_id=c.sid and b.cou_id=2
where a.score>b.score;
#总结:
#多重join的话,带where条件的join应该放在最后。
#3.查询同时存在" 01 "课程和" 02 "课程的情况
select t1.* from t_grade t1
inner join t_grade t2
on t1.stu_id=t2.stu_id
inner join t_grade t3
on t2.stu_id=t3.stu_id and t2.cou_id='01' and t3.cou_id='02'
#4.查询存在" 01 "课程但,存在也可能不存在" 02 "课程的情况(不存在时显示为 null )
select t1.* from t_grade t1
inner join t_grade t2
on t1.stu_id=t2.stu_id
left join t_grade t3
on t2.stu_id=t3.stu_id and t3.cou_id='02'
where t2.cou_id='01';
#总结:
#在左外连接中,不能在on中对左表进行过滤,且必须对右表过滤(其他外连接类似)。
#任何连接查询,on中都不能过滤空值。
#5.查询不存在" 01 "课程但存在" 02 "课程的情况
select a.*,b.cou_id,b.score from t_grade a
left join t_grade b
on a.stu_id=b.stu_id and b.cou_id=1
where a.cou_id=2 and b.cou_id is null;
#总结
#所谓的不存在,因该理解成"可能不存在+该字段为null",而可能不存在即为左右外连接
#on子句不要做控制过滤。
#6.查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
#第一种方式
select a.sid,a.sname,b.平均成绩 from t_student a
inner join (select stu_id,avg(score)平均成绩 from t_grade group by stu_id) b
on a.sid=b.stu_id
where b.平均成绩>=60;
#第二种方式:不含子查询
select t1.sid '学生编号',t1.sname '学生姓名',avg(t2.score) '平均成绩' from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
group by t1.sid ,t1.sname
having avg(t2.score)>=60
#总结:
#having中的过滤不能移到on中,因为on执行时group by还未执行。
#子查询和连接查询互转过程中group by 字段可能会改变,在spark/hive/调优可以借助这一点
#7.查询在 grade表存在成绩的学生信息
select t1.* from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
group by t2.stu_id
#对某个字段去重可以对它执行distinct也可以group by
#8.查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
select
t1.sid '学生编号',t1.sname '学生姓名',count(t2.cou_id) '选课总数',sum(t2.score) '所有课程总成绩' from t_student t1
left join t_grade t2
on t1.sid=t2.stu_id
group by t1.sid,t1.sname
#9查询「李」姓老师的数量
select count(tea_name) from t_teacher where tea_name like '李%';
#总结:
#%:通配任意个字符 _:通配一个字符
#10.查询学过「李四」老师授课的同学的信息
select t4.* from t_teacher t1
inner join t_course t2
on t1.tea_id=t2.tea_id and t1.tea_name='李四'
inner join t_grade t3
on t2.cou_id=t3.cou_id
inner join t_student t4
on t3.stu_id=t4.sid ;
#11.查询没有学全所有课程的同学的信息
select t1.sid,t1.sname,t1.sage,t1.ssex from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
group by t1.sid,t1.sname,t1.sage,t1.ssex
having count(t2.cou_id)<(select count(cou_id) from t_course)
#返回一个值或多个值的子查询无法转成连接查询。
#12.查询至少有一门课与学号为" 08 "的同学所学相同的同学的信息
select t1.* from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
where t1.sid!='08' and t2.cou_id in (select cou_id from t_grade where stu_id='08');
#distinct必须位于select子句的最前端
#in和=any可以完成一样的功能
#<> != 都表示不等于
#13.查询和" 01 "号的同学学习的课程完全相同的其他同学的信息
select t1.* from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id and t1.sid!='01'
group by t1.sid,t1.sname,t1.sage,t1.ssex
having group_concat(t2.cou_id order by t2.cou_id asc)=(select group_concat(cou_id order by cou_id asc) from t_grade where stu_id='01')
#group_concat函数可以将在组内将某个字段的值按要求全部连接起来
select stu_id,group_concat(cou_id order by cou_id separator '-') from t_grade group by stu_id;
#14.查询没学过"张三"老师讲授的任一门课程的学生姓名
select t1.sname from t_student t1
left join
(
select stu_id from t_grade t3
inner join t_course t4 on t3.cou_id=t4.cou_id
inner join t_teacher t5 on t4.tea_id=t5.tea_id and t5.tea_name='张三'
)t2
on t1.sid=t2.stu_id where t2.stu_id is null;
#15.查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
select t1.sid,t1.sname,avg(t2.score)'平均成绩' from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
group by t1.sid,t1.sname
having sum(if(t2.score>=60,0,1))>=2;
#16.检索" 01 "课程分数小于 60,按分数降序排列的学生信息
select t1.*,t2.score from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
where t2.cou_id='01' and t2.score<60
order by t2.score desc
#17.按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
select t1.*,t3.cou_id,t3.score,t2.avg_score from t_student t1
inner join
(select stu_id,avg(score) avg_score from t_grade group by stu_id) t2
on t1.sid=t2.stu_id
inner join t_grade t3
on t1.sid=t3.stu_id
order by t2.avg_score desc;
#18.查询各科课程ID,课程name,最高分、最低分和平均分,选修人数,及格率,中等率,优良率,优秀率
#先按人数降序,再按课程号升序排列
#及格为>=60,中等为:70-80,优良为:80-90,优秀为:>=90
select cou_id,
max(score) '最高分',
min(score) '最低分',
avg(score) '平均分',
count(stu_id) '选修人数',
(sum(if(score>=60,1,0))/count(stu_id)) '及格率',
(sum(if(score>=70 and score<80,1,0))/count(stu_id)) '中等率',
(sum(if(score>=80 and score<90,1,0))/count(stu_id)) '优良率',
(sum(if(score>=90,1,0))/count(stu_id)) '优秀率'
from t_grade group by cou_id
order by count(stu_id) desc,cou_id asc;
#19.按各科成绩进行排序,并显示排名, Score 重复时保留名次空缺
select t1.cou_id,t1.stu_id,t1.score,
(select count(*) from t_grade where cou_id=t1.cou_id and score>t1.score)+1 rank
from t_grade t1
order by t1.cou_id asc,rank asc;
#20.查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
SELECT t.stu_id, t.sum_score, (@rank := @rank + 1) rank FROM
(SELECT stu_id, sum(score) sum_score FROM t_grade GROUP BY stu_id ) t
inner join (select @rank:= 0) t2 on 1=1
order by sum_score desc;
#21.统计各科成绩各分数段人数:课程编号,课程名称,[100-85],[85-70],[70-60],[60-0] 及所占百分比
select t1.cou_id,t2.cou_name,
sum(if(t1.score<=100 and t1.score>85,1,0))/count(stu_id) as'100-85',
sum(if(t1.score<=85 and t1.score>70,1,0))/count(stu_id) '85-70',
sum(if(t1.score<=70 and t1.score>60,1,0))/count(stu_id) '70-60',
sum(if(t1.score<=60,1,0))/count(stu_id) '60-0'
from t_grade t1
inner join t_course t2
on t1.cou_id=t2.cou_id
group by t1.cou_id,t2.cou_name;
#22.查询各科成绩前三名的记录(要考虑排名重复的情况)
select t1.* from t_grade t1
where (select count(*) from t_grade where cou_id=t1.cou_id and score>t1.score)<3
order by t1.cou_id asc,t1.score desc;
#23.查询每门课程被选修的学生数
select cou_id,count(stu_id) from t_grade group by cou_id;
#24.查询出只选修两门课程的学生学号和姓名
select t1.sid,t1.sname from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
group by t1.sid,t1.sname
having count(t2.cou_id)=2;
#25.查询男生、女生人数
select ssex,count(*) from t_student group by ssex;
#26.查询名字中含有「累」字的学生信息
select * from t_student where sname like '%雷%';
#27.查询同名学生名单,并统计同名人数
select t1.*,(select count(*) from t_student where sname=t1.sname) from t_student t1
where sid in
(
select t1.sid from t_student t1 inner join t_student t2 on t1.sname=t2.sname and t1.sid!=t2.sid
);
####子查询已经保证同名不同sid,select子句中查同名人数即可,不用考虑id不同。
#28.查询 1990 年出生的学生名单
select * from t_student where year(sage)='1990'
#29.查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
select cou_id,avg(score) from t_grade group by cou_id order by avg(score) desc,cou_id asc;
#30.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
select t1.sid,t1.sname,avg(t2.score) from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
group by t1.sid,t1.sname
having avg(t2.score)>=85;
#31.查询课程名称为「数学」,且分数低于 60 的学生姓名和分数
select t3.sname,t2.cou_name,t1.score from t_grade t1
inner join t_course t2
on t1.cou_id=t2.cou_id and t2.cou_name='数学' and t1.score<60
inner join t_student t3
on t1.stu_id=t3.sid;
#32.查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
select t1.sid,t2.cou_id,t2.score from t_student t1
left join t_grade t2
on t1.sid=t2.stu_id
left join t_course t3
on t2.cou_id=t3.cou_id
#要保证连接字段中的null,第二次连接必须用left join
#33.查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
select t3.sname,t2.cou_name,t1.score from t_grade t1
inner join t_course t2
on t1.cou_id=t2.cou_id and t1.score>70
inner join t_student t3
on t1.stu_id=t3.sid
#34.查询存在不及格的课程
select distinct(t1.cou_id),t2.cou_name from t_grade t1
inner join t_course t2
on t1.cou_id=t2.cou_id and t1.score<60
#35.查询课程编号为 01 且课程成绩在 80 分以上的学生的学号和姓名
select t1.sid,t1.sname from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id and t2.cou_id='01' and t2.score >= 80
#36.求每门课程的学生人数
select cou_id,count(*) from t_grade group by cou_id;
#37.成绩不重复,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
select t1.*,t2.cou_id,t2.score from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id
inner join t_course t3
on t2.cou_id=t3.cou_id
inner join t_teacher t4
on t3.tea_id=t4.tea_id
where t4.tea_name='张三'
order by t2.score desc limit 1
#最高最低不一定max或min,也可以排序加limit
#38.成绩有重复的情况下,查询选修「张三」老师所授课程的学生中,成绩最高的学生信息及其成绩
select t1.*,t2.score from t_student t1
inner join t_grade t2
on t1.sid=t2.stu_id and t2.cou_id in
(
select t3.cou_id from t_course t3 inner join t_teacher t4 on t3.tea_id=t4.tea_id and t4.tea_name='张三'
)
where (select count(*) from t_grade where cou_id=t2.cou_id and score>t2.score)<1;
#39.查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
select t1.stu_id,t1.cou_id,t1.score from t_grade t1
inner join t_grade t2
on t1.stu_id=t2.stu_id and t1.score=t2.score and t1.cou_id!=t2.cou_id
group by t1.stu_id,t1.cou_id,t1.score
#40.查询每门功成绩最好的前两名 (要考虑到排名重复的情况)
select t1.* from t_grade t1
where
(select count(*) from t_grade t where t.cou_id=t1.cou_id and score>t1.score)<2
order by t1.cou_id asc,t1.score desc ;
#41.统计每门课程的学生选修人数(超过 5 人的课程才统计)。
select cou_id,count(stu_id) from t_grade group by cou_id having count(stu_id)>5;
#42.检索至少选修两门课程的学生学号
select stu_id from t_grade group by stu_id having count(cou_id)>=2;
#43.查询选修了全部课程的学生信息
select t1.* from t_student t1
inner join (
select stu_id from t_grade group by stu_id having count(cou_id)=(select count(*) from t_course)
)t2
on t1.sid=t2.stu_id;
#44.查询各学生的年龄,只按年份来算
select year(now())-year(sage) from t_student;
#45.按照出生日期来算,当前月日 < 出生年月的月日则,年龄减一
select timestampdiff(year,sage,now()) from t_student;
#46.查询本周过生日的学生
select * from t_student
where UNIX_TIMESTAMP(concat_ws('-',year(now()),month(sage),day(sage))) between
UNIX_TIMESTAMP(date_sub(now(),interval dayofweek(now())-1 day)) and
UNIX_TIMESTAMP(date_add(now(),interval 7-dayofweek(now()) day));
#47.查询下周过生日的学生
select * from t_student
where UNIX_TIMESTAMP(concat_ws('-',year(now()),month(sage),day(sage))) between
UNIX_TIMESTAMP(date_sub(now(),interval dayofweek(now())-8 day)) and
UNIX_TIMESTAMP(date_add(now(),interval 14-dayofweek(now()) day));
#48.查询本月过生日的学生
select * from t_student where month(sage)=month(now());
#49-.查询下月过生日的学生(下个月可能是下一年)
select * from t_student
where if(month(now())=12,12-month(sage),month(sage))+1=month(now());
行列转换
create table row2col(
name varchar(22),
subj varchar(22),
score int(4)
)charset=utf8
truncate table row2col;
insert into row2col values('张三','yuwen',82);
insert into row2col values('张三','shuxue',90);
insert into row2col values('张三','yingyu',78);
insert into row2col values('李四','yuwen',82);
insert into row2col values('李四','shuxue',90);
insert into row2col values('李四','yingyu',78);
insert into row2col values('王五','yuwen',82);
insert into row2col values('王五','shuxue',90);
insert into row2col values('王五','yingyu',78);
select * from row2col;
行转列
select t1.name,t1.score yuwen,t2.score shuxue,t3.score yingyu from
(select name,score from row2col where subj='yuwen')t1
inner join
(select name,score from row2col where subj='shuxue')t2
on t1.name=t2.name
inner join
(select name,score from row2col where subj='yingyu')t3
on t2.name=t3.name;
列换行
select name,'yuwen' as subj,yuwen from col2row
union all
select name,'shuxue' as subj,shuxue from col2row
union all
select name,'yingyu' as subj,yingyu from col2row
order by name