1.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`)
);
-- 课程表
CREATE TABLE `Course`(
`c_id` VARCHAR(20),
`c_name` VARCHAR(20) NOT NULL DEFAULT '',
`t_id` VARCHAR(20) NOT NULL,
PRIMARY KEY(`c_id`)
);
-- 教师表
CREATE TABLE `Teacher`(
`t_id` VARCHAR(20),
`t_name` VARCHAR(20) NOT NULL DEFAULT '',
PRIMARY KEY(`t_id`)
);
-- 成绩表
CREATE TABLE `score` (
`s_id` varchar(20) NOT NULL COMMENT '学生id',
`c_id` varchar(20) NOT NULL COMMENT '课程id',
`s_score` int(3) DEFAULT NULL COMMENT '成绩',
PRIMARY KEY (`s_id`,`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 插入学生表测试数据
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' , '女');
-- 课程表测试数据
insert into Course values('01' , '语文' , '02');
insert into Course values('02' , '数学' , '01');
insert into Course values('03' , '英语' , '03');
-- 教师表测试数据
insert into Teacher values('01' , '张三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');
-- 成绩表测试数据
insert into Score values('01' , '01' , 80);
insert into Score values('01' , '02' , 90);
insert into Score values('01' , '03' , 99);
insert into Score values('02' , '01' , 70);
insert into Score values('02' , '02' , 60);
insert into Score values('02' , '03' , 80);
insert into Score values('03' , '01' , 80);
insert into Score values('03' , '02' , 80);
insert into Score values('03' , '03' , 80);
insert into Score values('04' , '01' , 50);
insert into Score values('04' , '02' , 30);
insert into Score values('04' , '03' , 20);
insert into Score values('05' , '01' , 76);
insert into Score values('05' , '02' , 87);
insert into Score values('06' , '01' , 31);
insert into Score values('06' , '03' , 34);
insert into Score values('07' , '02' , 89);
insert into Score values('07' , '03' , 98);
1.1查询’01’课程比’02’课程成绩高的学生的信息及课程分数
-- 方法1
select
a.*
,b.s_score as 1_score
,c.s_score as 2_score
from Student a
join Score b on a.s_id = b.s_id and b.c_id = '01' -- 两个表通过学号连接,指定01
left join Score c on a.s_id = c.s_id and c.c_id='02' or c.c_id is NULL -- 指定02,或者c中的c_id直接不存在
-- 为NULL的条件可以不存在,因为左连接中会直接排除c表中不存在的数据,包含NULL
where b.s_score > c.s_score; -- 判断条件
-- 方法2:直接使用where语句
select
a.*
,b.s_score as 1_score
,c.s_score as 2_score
from Student a, Score b, Score c
where a.s_id=b.s_id -- 列出全部的条件
and a.s_id=c.s_id
and b.c_id='01'
and c.c_id='02'
and b.s_score > c.s_score; -- 前者成绩高
1.2查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
-- 执行顺序:先执行分组,再执行avg平均操作
SELECT
b.s_id,
b.s_name,
AVG( a.s_score ) AS avgs,
round( avg( a.s_score ), 2 ) AS avg_score -- 保留两位小数
FROM
student b
LEFT JOIN score a ON b.s_id = a.s_id
-- JOIN score a ON b.s_id = a.s_id -- 不用left join 则不会查出没有成绩的学生
GROUP BY
b.s_id
HAVING
avgs >= 60
ORDER BY
avgs DESC;
1.3查询学过张三老师授课的同学的信息
-- 方法1,常用
select s.* from Teacher t
left join Course c on t.t_id=c.t_id -- 教师表和课程表
left join Score sc on c.c_id=sc.c_id -- 课程表和成绩表
left join Student s on s.s_id=sc.s_id -- 成绩表和学生信息表
where t.t_name='张三';
-- 方法2
select s1.*
from Student s1
join Score s2
on s1.s_id=s2.s_id
where s2.c_id in (
select c_id from Course c where t_id=( -- 1. 通过老师找出其对应的课程
select t_id from Teacher t where t_name='张三'
)
)
1.4找出没有学过张三老师课程的学生
使用反查:先查出有张三课的学生,再去过滤
-- 方法1
select *
from Student s1
where s1.s_id not in (
SELECT
s2.s_id
FROM
Student s2
JOIN Score s3 ON s2.s_id = s3.s_id
WHERE
s3.c_id IN (
SELECT
c.c_id
FROM
Course c
JOIN Teacher t ON c.t_id = t.t_id
WHERE
t_name = '张三'
)
);
-- 方法2
SELECT
*
FROM
Student s1
WHERE
s1.s_id NOT IN (
SELECT
s.s_id
FROM
Teacher t
LEFT JOIN Course c ON t.t_id = c.t_id -- 教师表和课程表
LEFT JOIN Score sc ON c.c_id = sc.c_id -- 课程表和成绩表
LEFT JOIN Student s ON s.s_id = sc.s_id -- 成绩表和学生信息表
WHERE
t.t_name = '张三'
);
-- 方法3,使用NOT EXISTS,请尽量不要使用not in(它会调用子查询),而尽量使用not exists(它会调用关联子查询)
SELECT
*
FROM
Student s1
WHERE
NOT EXISTS (
SELECT
1
FROM
(
SELECT
s.s_id,
t.t_name
FROM
Teacher t
LEFT JOIN Course c ON t.t_id = c.t_id -- 教师表和课程表
LEFT JOIN Score sc ON c.c_id = sc.c_id -- 课程表和成绩表
LEFT JOIN Student s ON s.s_id = sc.s_id -- 成绩表和学生信息表
WHERE
t.t_name = '张三'
) c
WHERE
c.s_id = s1.s_id
);
1.5查询学过编号为01,并且学过编号为02课程的学生信息
-- 方法1:通过自连接实现
SELECT
s1.*
FROM
Student s1
WHERE
s_id IN (
SELECT
s2.s_id
FROM
Score s2
JOIN Score s3 ON s2.s_id = s3.s_id
WHERE
s2.c_id = '01'
AND s3.c_id = '02'
);
-- 方法2:直接通过where语句实现
SELECT
s1.*
FROM
Student s1,
Score s2,
Score s3
WHERE
s1.s_id = s2.s_id
AND s1.s_id = s3.s_id
AND s2.c_id = 01
AND s3.c_id = 02;
-- 方法3:两个子查询
-- 1. 先查出学号
SELECT
sc1.s_id
FROM
( SELECT * FROM Score s1 WHERE s1.c_id = '01' ) sc1,
( SELECT * FROM Score s1 WHERE s1.c_id = '02' ) sc2
WHERE
sc1.s_id = sc2.s_id;
-- 2.找出学生信息
SELECT
*
FROM
Student
WHERE
s_id IN (
SELECT
sc1.s_id -- 指定学号是符合要求的
FROM
( SELECT * FROM Score s1 WHERE s1.c_id = '01' ) sc1,
( SELECT * FROM Score s1 WHERE s1.c_id = '02' ) sc2
WHERE
sc1.s_id = sc2.s_id
);
-- 方法4,使用EXISTS
SELECT
s1.*
FROM
Student s1
WHERE
EXISTS ( SELECT 1 FROM score c WHERE c.s_id = s1.s_id AND c.c_id = '01' )
AND EXISTS ( SELECT 1 FROM score c2 WHERE c2.s_id = s1.s_id AND c2.c_id = '02' );
1.6查询学过01课程,但是没有学过02课程的学生信息
-- 方法1:根据两种修课情况来判断
SELECT
s1.*
FROM
Student s1
WHERE
s1.s_id IN ( SELECT s_id FROM Score WHERE c_id = '01' ) -- 修过01课程,要保留
AND s1.s_id NOT IN ( SELECT s_id FROM Score WHERE c_id = '02' );-- 哪些人修过02,需要排除
-- 方法2:先把06号学生找出来
SELECT
*
FROM
Student
WHERE
s_id IN ( SELECT s_id FROM Score WHERE c_id = '01' -- 修过01课程的学号
AND s_id NOT IN ( SELECT s_id -- 同时学号不能在修过02课程中出现
FROM Score WHERE c_id = '02' ) );
-- 方法3,使用 EXISTS ,NOT EXISTS
SELECT
s1.*
FROM
Student s1
WHERE
EXISTS ( SELECT 1 FROM score c WHERE c.s_id = s1.s_id AND c.c_id = '01' )
AND NOT EXISTS ( SELECT 1 FROM score c2 WHERE c2.s_id = s1.s_id AND c2.c_id = '02' );
1.7查询没有学全所有课程的同学的信息
-- 方法一:
SELECT
*
FROM
student
WHERE
s_id IN ( SELECT s_id FROM score GROUP BY s_id HAVING COUNT( s_id ) != 3 );
-- 方法二:
SELECT
*
FROM
student d
WHERE
d.s_id IN (
SELECT
e.s_id
FROM
score e
WHERE
e.s_id NOT IN (
SELECT
a.s_id
FROM
score a
JOIN score b ON a.s_id = b.s_id
AND b.c_id = '02'
JOIN score c ON a.s_id = c.s_id
AND c.c_id = '03'
WHERE
a.c_id = '01'
)
);
-- 上述两种方法结果都少了没有选课的8号学生,但看具体条件是否需要查出
-- 方法3,使用 EXISTS ,先查出已经学完所有的人,再反查,就能查出8
SELECT
*
FROM
student d
WHERE
d.s_id NOT IN (
SELECT
s1.s_id
FROM
Student s1
WHERE
EXISTS ( SELECT 1 FROM score c WHERE c.s_id = s1.s_id AND c.c_id = '01' )
AND EXISTS ( SELECT 1 FROM score c2 WHERE c2.s_id = s1.s_id AND c2.c_id = '02' )
AND EXISTS ( SELECT 1 FROM score c3 WHERE c3.s_id = s1.s_id AND c3.c_id = '03' ));
1.8查询和"01"号的同学学习的课程完全相同的其他同学的信息
-- 方法1
-- 将group by产生的同一个分组中的值连接起来,返回一个字符串结果
-- 再去匹配字符串一样的学生(注意字符拼接前要排序)
SELECT
t1.s_id
FROM
( SELECT s_id, group_concat( c_id ORDER BY c_id ) AS a FROM score GROUP BY s_id ) t1
WHERE t1.s_id != '01' and
t1.a = ( SELECT group_concat( c_id ORDER BY c_id ) AS a FROM score WHERE s_id = '01' GROUP BY s_id );
-- 方法2
SELECT* FROM student
WHERE
s_id IN (
SELECT DISTINCT
s_id
FROM
score
WHERE
s_id != '01'
AND c_id IN ( SELECT c_id FROM score WHERE s_id = '01' )
GROUP BY
s_id
HAVING
COUNT( 1 )=(
SELECT
COUNT( 1 )
FROM
score
WHERE
s_id = '01'
)
) ;
1.9 查询没学过张三老师讲过任何一门课的学生
SELECT student.* FROM student WHERE
student.s_id NOT IN (
SELECT s.s_id FROM score s WHERE
s.c_id IN ( SELECT course.c_id FROM course,teacher WHERE teacher.t_id =course.t_id and teacher.t_name = '张三' ) GROUP BY s.s_id );