MySQL练习(1)

说明: 本文是本人的练习sql的学习笔记,sql自己写的,并且通过对比网上别人的sql来学习多种方式实现,锻炼自己多种解法的能力,并学习别人的语句的优美的地方。题目等都来自这里,https://blog.csdn.net/fashion2014/article/details/78826299

原理

执行顺序

  1. from自居组装来自不同数据源的数据;
  2. where子句基于指定的条件堆记录行进行帅选
  3. group by 子句将数据划分为多个分组
  4. 使用聚集函数进行计算
  5. 使用having子句帅选分组;
  6. 计算所有的表达式
  7. select所有的字段
  8. order by堆结果集进行排序

UNION用法

union的用法,也就是UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。
函数:group_concat(),手册上说明:该函数返回带有来自一个组的连接的非NULL值的字符串结果。

CASE WHEN用法

CASE WHEN condition THEN result 
WHEN condition THEN result 
.............
[WHEN ...] 
[ELSE result] 
END

CASE 子句可以用于任何表达式可以有效存在的地方。 condition 是一个返回boolean 的表达式。 如果结果为真,那么 CASE 表达式的结果就是符合条件的 result。 如果结果为假,那么以相同方式搜寻任何随后的 WHEN 子句。 如果没有 WHEN condition 为真,那么 case 表达式的结果就是在 ELSE 子句里的值。 如果省略了 ELSE 子句而且没有匹配的条件, 结果为 NULL。
或其语法为:
简单Case函数
CASE sex
WHEN ‘1’ THEN ‘男’
WHEN ‘2’ THEN ‘女’
ELSE ‘其他’ END

定义用户变量的方式:select @变量名

对用户变量赋值有两种方式,一种是直接用"=“号,另一种是用”:="号。其区别在于使用set命令对用户变量进行赋值时,两种方式都可以使用;当使用select语句对用户变量进行赋值时,只能使用":=“方式,因为在select语句中,”="号被看作是比较操作符
(@i:=@i+1) 也可以写成 @i:=@i+1 ,加括号是为了视觉上看这结构更清楚些。在定义好一个变量后每次查询都会给这个变量自增,而我们每次执行查询语句获取结果后就不需要这个变量自增了,所以要把它重置为0,在表名后用逗号分格下使用 (SELECT @i:=0) as i 就可以了,说下这个as i为什么要这样用,是因为派生表必须需要一个别名,这个就是做它的别名,可以任意字符。

练习

建表语句:

课程表
CREATE TABLE `course`  (
  `c_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `c_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `t_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`c_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

老师表
CREATE TABLE `teacher`  (
  `t_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `t_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`t_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

学生表
CREATE TABLE `student`  (
  `s_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `s_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `s_birth` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `s_sex` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  PRIMARY KEY (`s_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

成绩表
CREATE TABLE `score`  (
  `s_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `c_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `s_score` int(3) DEFAULT NULL,
  PRIMARY KEY (`s_id`, `c_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
测试数据
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 `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 `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);

course
图片
student
图片
成绩表score
图片
老师表 teacher
图片

建议拿张纸把每张表的关系记录下,这样方便写sql的时候思考,如下图

图片

1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数

– 思路: 这里要理解01课程和02课程都是同一样表,也就是说如果要比较两者的话,得建两个一样的表才能比较

-- 法一
SELECT
	s.*,
	s1.s_score AS "01_score",
	s2.s_score AS "02_score" 
FROM
	student s
	inner JOIN score s1 ON s1.s_id = s.s_id 
	AND s1.c_id = "01"
	LEFT JOIN score s2 ON s2.s_id = s.s_id 
	AND s2.c_id = "02" 
WHERE
	s1.s_score > s2.s_score
-- 法二
SELECT
	s.*,
	s1.s_score AS "01_score",
	s2.s_score AS "02_score" 
FROM
	student s,
	score s1,
	score s2 
WHERE
	s.s_id = s1.s_id 
	AND s.s_id = s2.s_id 
	AND s1.c_id = "01" 
	AND s2.c_id = "02" 
	AND s1.s_score > s2.s_score

结果:
图片

2、查询"01"课程比"02"课程成绩低的学生的信息及课程分数

这里第一个用inner join 也就是匹配只有学生信息有的数据才显示,第二个则必须用left join,即没匹配的也要显示出来;

SELECT
	s.*,
	s1.s_score AS "01_score",
	s2.s_score AS "02_score" 
FROM
	student s
	inner JOIN score s1 ON s1.s_id = s.s_id 
	AND s1.c_id = "01"
	LEFT JOIN score s2 ON s2.s_id = s.s_id 
	AND s2.c_id = "02" 
WHERE
	s1.s_score < s2.s_score

结果:
图片

3、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩

注意,使用聚合函数的时候,必须要有group by 分组,执行顺序是先分组再过滤,
– having的执行顺序在group by之后,而where执行顺序在group by 之前,而我们是要分组要统计出来的平均值进行比较大于60才显示

select s.s_id,s.s_name, ROUND(AVG(s1.s_score),2)  as s_avg
from student s 
inner  join score s1 on s1.s_id = s.s_id
group by s.s_id
having
s_avg >= 60

结果:
图片

4. 查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩,测试数据中t_id为8的没有成绩

法一:
注意: 这里用到了union的用法,也就是UNION 内部的每个 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每个 SELECT 语句中的列的顺序必须相同。

select s.s_id,s.s_name, ROUND(AVG(s1.s_score),2)  as s_avg
from student s 
inner  join score s1 on s1.s_id = s.s_id
group by s.s_id
having
s_avg < 60 
union 
(select s.s_id,s.s_name, '0'  as s_avg
from student s 
where s.s_id not in(select s_id from score ))
法二(相对于法一来说更加简洁):
SELECT
	s.s_id,
	s.s_name,
	ROUND( IFNULL( AVG( sc.s_score ), 0 ), 2 ) AS s_avg 
FROM
	student s
	LEFT JOIN score sc ON sc.s_id = s.s_id 
GROUP BY
	s.s_id 
HAVING
s_avg < 60

5、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩
注意这里不能用inner join 去连接哦,因为是所有学生,08号学生是没有课程,所以用innerjoin的话,只有匹配到的数据才显示

SELECT
	s.s_id,
	s.s_name,
	count( s1.c_id ) AS sum_course,
	SUM( s1.s_score ) AS sum_score 
FROM
	student s
	LEFT JOIN score s1 ON s1.s_id = s.s_id 
GROUP BY
	s.s_id

结果:
图片

6、查询"李"姓老师的数量

思路,也就是统计出匹配后出来的t_id

SELECT
	count( t_id ) 
FROM
	teacher t 
WHERE
	t.t_name LIKE "张%"

图片

7、查询学过"张三"老师授课的同学的信息

解法一: 以老师授课为主表进行关联

SELECT
	s.* 
FROM
	teacher t
	INNER JOIN course c1 ON c1.t_id = t.t_id
	INNER JOIN score s1 ON s1.c_id = c1.c_id
	INNER JOIN student s ON s.s_id = s1.s_id 
WHERE
	t.t_name = "张三"

解法二: 以学生为主表进行关联

SELECT
	a.* 
FROM
	student a
	JOIN score b ON a.s_id = b.s_id 
WHERE
	b.c_id IN ( SELECT c_id FROM course WHERE t_id = ( SELECT t_id FROM teacher WHERE t_name = '张三' ) );

图片

8、查询没学过"张三"老师授课的同学的信息

思路: 只要我们找出张三老师教过那些学生,然后在在学生表中排除这些学生,剩下的就是没学过张三老师的学生;----》 变成我们要找出张三老师教过哪些学生的问题,也就是我们可以课程表和老师表关联,找出张三老师教学的课程 c_id------》在成绩表中选出等于该课程的学生id
-------》 学生表中排除选出的这些学生id

SELECT
	s.* 
FROM
	student s 
WHERE
	s.s_id NOT IN (
SELECT
	s1.s_id 
FROM
	score s1 
WHERE
	c_id = ( SELECT c_id FROM course c1  JOIN teacher t ON t.t_id = c1.t_id WHERE t.t_name = "张三" ) 
	)

图片

9、查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息

思路: 这里课程有两个条件,并且都是一个字段的问题,那么就要有两个相同的表,我们才可以进行比较;
解法1:

SELECT
	st.* 
FROM
	student st
	INNER JOIN score sc1 ON sc1.s_id = st.s_id
	LEFT JOIN score sc2 ON sc2.s_id = st.s_id 
WHERE
	sc1.c_id = "01" 
	AND sc2.c_id = "02"

解法2

select a.* 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';

图片

10、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息

思路: 好像如果是都有的话,我们可以用表连接,如果不是都有的话,那么不能用表连接,而是通过条件判断来获取的

SELECT DISTINCT
	st.* 
FROM
	student st 
WHERE
  st.s_id IN ( SELECT sc1.s_id FROM score sc1 WHERE sc1.c_id = "01" )                   
  AND st.s_id NOT IN ( SELECT sc.s_id FROM score sc WHERE sc.c_id IN ( "02" ) )

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值