SQL50道练习

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/xjh163/article/details/98852916

最好的学习方法就是保持感觉,要多练习,多敲代码,多思考,同一个问题有不同的解法
下面我们来实际操作
建立三个表
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

猜你喜欢

转载自blog.csdn.net/xjh163/article/details/98852916