mysql练习(50题)

使用mysql的5.7.23版本

mysql数据准备:
建表
/*
-- 建表
-- 学生表
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`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 课程表
CREATE TABLE `Course`(
    `c_id`  VARCHAR(20),
    `c_name` VARCHAR(20) NOT NULL DEFAULT '',
    `t_id` VARCHAR(20) NOT NULL,
    PRIMARY KEY(`c_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 教师表
CREATE TABLE `Teacher`(
    `t_id` VARCHAR(20),
    `t_name` VARCHAR(20) NOT NULL DEFAULT '',
    PRIMARY KEY(`t_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 成绩表
CREATE TABLE `Score`(
    `s_id` VARCHAR(20),
    `c_id`  VARCHAR(20),
    `s_score` INT(3),
    PRIMARY KEY(`s_id`,`c_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
向表中插入数据
准备产生随机数函数:
-- 产生随机整数(0-100)
delimiter $
	create function ran_num() returns int(5)
		begin
			declare i int default 0;
			set i =floor( rand()*100 ) ;
		return i ;
		end $

-- 插入学生表测试数据
/*
delimiter $ 
create procedure insert_stu(in dno_start int(10) ,in data_times int(10))
		begin
			declare i int default 0;
			set autocommit = 0 ;
			repeat
			
				insert into Student values(CONCAT('0',i) ,CONCAT('学生0',i),CONCAT('199',mod(i,10),'-0',mod(i,10),'-0',mod(i,10)),mod(i,2)) ;
				set i=i+1 ;
				until i=data_times
			end repeat ;
		commit ;		
		end $
delimiter ; 
call insert_stu(0,1000) ;*/
-- 课程表测试数据
/*
delimiter $ 
create procedure insert_course(in dno_start int(10) ,in data_times int(10))
		begin
			declare i int default 0;
			set autocommit = 0 ;
			repeat
insert into Course values(CONCAT('0',i), CONCAT('课程0',i) , CONCAT('0',i));
				set i=i+1 ;
				until i=data_times
			end repeat ;
		commit ;		
		end $
delimiter ; 
call insert_course(0,10) ;*/
 
-- 教师表测试数据
/*
delimiter $ 
create procedure insert_teacher(in dno_start int(10) ,in data_times int(10))
		begin
			declare i int default 0;
			set autocommit = 0 ;
			repeat
insert into Teacher values(CONCAT('0',i) ,CONCAT('老师0',i)) ;
				set i=i+1 ;
				until i=data_times
			end repeat ;
		commit ;		
		end $
delimiter ; 
call insert_teacher(0,10) ;*/
 
-- 成绩表测试数据
/*
delimiter $ 
create procedure insert_score(in dno_start int(10) ,in data_times int(10))
		begin
			declare i int default 0;
			declare j int default 0;
			set autocommit = 0 ;
			repeat
					set j=0;
					repeat
							insert into Score values(CONCAT('0',i) , CONCAT('0',j) , ran_num());
							set j=j+1 ;
							until j=10
					end repeat ;
			set i=i+1 ;
			until i=data_times
			end repeat ;
		commit ;		
		end $
delimiter ; 
call insert_score(0,1000) ;
*/

如果出现错误:Lock wait timeout exceeded; try restarting transaction 点击该链接

表中数据量:
SELECT count(1) from score; -- 10000
SELECT count(1) from student; -- 1000
SELECT count(1) from course; -- 10
SELECT count(1) from teacher;-- 10
1、查询"01"课程比"02"课程成绩高的学生的信息及01和02课程分数
-- ans1:
SELECT stu.* ,t.score1,t.score2  from Student stu ,(
SELECT s1.s_id,s1.s_score score1,s2.s_score score2 from (SELECT s_id,s_score  from Score where c_id='01') as s1,(SELECT s_id,s_score  from Score where c_id='02') as s2
where s1.s_score>s2.s_score and s1.s_id=s2.s_id) as t
where stu.s_id=t.s_id;

-- ans2:
SELECT s.*,t.score1,t.score2 from 
(SELECT s1.s_id,s1.s_score score1,s2.s_score score2 from (SELECT s_id,s_score  from Score where c_id='01') as s1,(SELECT s_id,s_score  from Score where c_id='02') as s2
where s1.s_score>s2.s_score and s1.s_id=s2.s_id) as t LEFT JOIN student s on t.s_id=s.s_id ;

-- ans3:
select a.* ,b.s_score as 01_score,c.s_score as 02_score from 
    Student a 
    join score b on a.s_id=b.s_id and b.c_id='01'
    left join score c on a.s_id=c.s_id and c.c_id='02' or c.c_id = NULL where b.s_score>c.s_score;

 show profiles;
-- 494条数据

下面是show profiles的结果
在这里插入图片描述
3条查询耗时差距不大

2.查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
-- ans1
 SELECT st.s_id,st.s_name,avgs from (SELECT ROUND(AVG(s_score),2) avgs,s_id from Score GROUP BY s_id HAVING avgs>=60 ) as t 
LEFT JOIN Student st on t.s_id=st.s_id;

-- ans2
 select b.s_id,b.s_name,ROUND(AVG(a.s_score),2) as avg_score from 
    student b 
    join score a on b.s_id = a.s_id
    GROUP BY b.s_id,b.s_name HAVING ROUND(AVG(a.s_score),2)>=60;

show profiles;
-- 129条数据

show profiles;
在这里插入图片描述
两个sql的查询耗时有数量级的差距

SHOW STATUS LIKE '%Handler_read_%';

ans1如图
在这里插入图片描述

ans2如图
在这里插入图片描述
可能原因:
ans1通过子查询过滤了数据,使得两个表join的笛卡尔积数量减少(mysql执行顺序from on join group by having select)

3.查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩-- (包括有成绩的和无成绩的)
-- ans1
 SELECT st.s_id,st.s_name,avgs from (SELECT ROUND(AVG(s_score),2) avgs,s_id from Score GROUP BY s_id HAVING avgs<60 ) as t 
LEFT JOIN Student st on t.s_id=st.s_id
UNION
SELECT s_id,s_name,0 from student st where s_id not in(SELECT s_id from score );

-- ans2
 SELECT st.s_id,st.s_name,avgs from (SELECT ROUND(AVG(s_score),2) avgs,s_id from Score GROUP BY s_id HAVING avgs<60 ) as t 
LEFT JOIN Student st on t.s_id=st.s_id
UNION
SELECT s_id,s_name,0 from student st where  not exists(SELECT s_id from score s where s.s_id=st.s_id );

-- ans3
select b.s_id,b.s_name,ROUND(AVG(a.s_score),2) as avg_score from 
    student b 
    left join score a on b.s_id = a.s_id
    GROUP BY b.s_id,b.s_name HAVING ROUND(AVG(a.s_score),2)<60
    union
select a.s_id,a.s_name,0 as avg_score from 
    student a 
    where a.s_id not in (
                select distinct s_id from score);

show profiles;
-- 871

在这里插入图片描述
ans1的in 和ans2的exists有数量级区别的的duration (in>>exists) 不知道为什么???
如果mysql更喜欢小表驱动大表(score表的数量>>student) in 是里面驱动外面,exists是主查询驱动子查询,与结果不一致

4.查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
-- ans1
SELECT st.s_id,st.s_name,t.counts,t.avgs from student st ,
(SELECT s_id, count(c_id) as counts, SUM(s_score) as avgs from score GROUP BY s_id) as t 
where st.s_id=t.s_id;
-- ans2
select a.s_id,a.s_name,count(b.c_id) as sum_course,sum(b.s_score) as sum_score from 
    student a 
    left join score b on a.s_id=b.s_id
    GROUP BY a.s_id,a.s_name;

show profiles;
-- 1000

show profiles;
在这里插入图片描述
结果:sql执行耗时数量级差别(ans1的子查询group by优于ans2主查询的group by,ans2先笛卡尔积group by的时候数据量比ans1的数据量少(少了几列)???)

发布了88 篇原创文章 · 获赞 58 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_37636695/article/details/104296673