Mysql
1、数据库的约束
1.1约束类型
什么是约束?
约束是数据库自动对数据进行合法性校验检查的一系列机制,目的是为了数据库中能避免被插入/修改一些非法的数据,数据库引入约束后执行效率会受影响,效率会降低很多
NOT NULL
:知识某列不能存储NULL值UNIQUE
:保证某列的每行必须有唯一的值,unique会让后续插入/修改数据时都先触发一次查询操作,确定当前记录是否存在DEFAULT
:规定没有给列赋值时的默认值PRIMARY KEY
:NOT NULL和UNIQUE的结合,确保某列有唯一标识,有助于更快速地找到表中的一个特定的记录,一张表中只能有一个primary keyFOREIGN KEY
:保证一个表中数据匹配另一个表中的值的参照完整性CHECK
:保证列中的值符合指定的条件
下面我们来进行逐一解释
1.2 NULL约束
创建表时,可以指定某列不为空
mysql> create table student
(id int not null,sn int,name varchar(20),qq_mail varchar(20));
-- 如果id列插入null类型的数据,则会报错
mysql> insert into student values(null,1,'lisi','ddd');
ERROR 1048 (23000): Column 'id' cannot be null
1.3 UNIQUE:唯一约束
指定sn列是唯一的,不重复的
mysql> create table student
(id int not null,sn int unique,name varchar(20),qq_mail varchar(20));
Query OK, 0 rows affected (0.02 sec)
-- 我们可以在以下代码看到,sn只能插入一次相同的值,重复插入会报错
mysql> insert into student values(1,1,'qqq','qqq');
Query OK, 1 row affected (0.01 sec)
mysql> insert into student values(1,1,'qqq','qqq');
ERROR 1062 (23000): Duplicate entry '1' for key 'sn'
mysql>
1.4 DEFAULT:默认值约束
指定插入数据时,name列为空,则默认值为unkown
create table student
(id int not null,sn int unique,name varchar(20) default 'unkown',qq_mail varchar(20));
-- 在下列代码可以看到name列没被插入,系统自动补成unkown
mysql> insert into student(id ,sn,qq_mail) values(2,2,'qqq');
Query OK, 1 row affected (0.01 sec)
mysql> select * from student;
+----+------+--------+---------+
| id | sn | name | qq_mail |
+----+------+--------+---------+
| 2 | 2 | unkown | qqq |
+----+------+--------+---------+
1 row in set (0.00 sec)
1.5 PRIMARY KEY:主键约束(重点)
指定id列为主键
mysql> create table student
(id int not null primary key,name varchar(20));
Query OK, 0 rows affected (0.01 sec)
如何保证主键唯一呢?
MySQL提供一种“自增主键”这样的机制,主键经常使用int/big int,我们插入数据的时候,不必手动指定主键值,由数据库服务器自己分配一个主键,从1开始,依次递增的分配主键的值
对于整数类型的主键,常搭配子增长auto_increment
来使用,插入数据对应字段不给值时(null,这里写作null其实是交给数据库服务器自行分配),使用最大值+1(相当于使用了一个变量来保存当前表的ID最大值,后续分配自增主键都是根据这个最大值分配的,如果手动指定的id也会更新最大值)
自动分配也有一定的局限性,如果是单个MySQL没问题,如果是一个分布式系统有多个MySQL服务器构成的集群,这个时候自增主键就不行了
-- 主键是NOT NULL和UNIQUE的结合,可以不用NOT NULL
create table student1
(id int primary key auto_increment,name varchar(20));
Query OK, 0 rows affected (0.01 sec)
-- 插入多条数据,不指定id,我们来看一下效果
mysql> insert into student1(name) values('qqq');
mysql> insert into student1(name) values('qqq');
mysql> insert into student1(name) values('qqq');
mysql> insert into student1(name) values('qqq');
mysql> select * from student1;
+----+------+
| id | name |
+----+------+
| 1 | qqq |
| 2 | qqq |
| 3 | qqq |
| 4 | qqq |
+----+------+
4 rows in set (0.00 sec)
-- 当我们指定了一个id,自增主键会更新最大值,我们来看下效果
mysql> insert into student1 values(11,'qqq');
Query OK, 1 row affected (0.00 sec)
mysql> insert into student1(name) values('qqq');
Query OK, 1 row affected (0.00 sec)
mysql> select * from student1;
+----+------+
| id | name |
+----+------+
| 1 | qqq |
| 2 | qqq |
| 3 | qqq |
| 4 | qqq |
| 11 | qqq |
| 12 | qqq |
+----+------+
6 rows in set (0.00 sec)
分布式唯一id:=时间戳+主机编号/机房编号+随机因子
+指的是字符串拼接,不是算数相加
1.6 FOREIGN KEY:外键约束(重点)
外键用于关联其他表的主键或唯一键,描述了两个表之间的关联关系,只有用到的才受约束。
语法:
foreign key (子表的列) reference 主表(列);
进一步解释:子表的列
表示当前哪个表的哪个列被约束,主表(列)
表示数据是被谁约束,也就是说,子表的列
要出自于主表后括号中的那一列
,references
表示当前这个表的这一列中的数据应该是出自另一个表的哪一列
- 例:classes表中的数据约束了student表中的数据,classes称为父表(约束别人的表),student称为子表(被人约束的表)
创建班级表classes,id为主键:
mysql> create table classes
(id int primary key auto_increment,
name varchar(20),
`desc` varchar(100));
创建学生表student,一个学生对应一个班级,一个班级对应多个学生,使用id为主键,classes_id为外键,关联班级表id
mysql> create table student
(id int primary key auto_increment,
sn int unique,
name varchar(20) default 'unkown',
qq_mail varchar(20),
classes_id int,
foreign key (classes_id) references classes(id));
Query OK, 0 rows affected (0.02 sec)
-- 我们可以看到如下代码
mysql> insert into classes(name,`desc`) values('qqq','aaa');
Query OK, 1 row affected (0.00 sec)
mysql> select * from classes;
+----+------+------+
| id | name | desc |
+----+------+------+
| 1 | qqq | aaa |
+----+------+------+
1 row in set (0.00 sec)
-- 在这里我们发现把一个学生的班级设置为2会错误,因为classes表中没有id为2这个班级
mysql> insert into student(name,classes_id) values('qqq',2);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db_test`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`classes_id`) REFERENCES `classes` (`id`))
-- 班级设置为1则正确
mysql> insert into student(name,classes_id) values('qqq',1);
Query OK, 1 row affected (0.00 sec)
mysql> select * from student;
+----+------+------+---------+------------+
| id | sn | name | qq_mail | classes_id |
+----+------+------+---------+------------+
| 2 | NULL | qqq | NULL | 1 |
+----+------+------+---------+------------+
1 row in set (0.00 sec)
要对父表进行修改/删除操作,如果当前被修改/删除的值已经被子表引用了,这样的操作会失败,外键约束始终要保持子表中的数据要在对应的父表的列中存在,此时万一把父表这条数据删除了,就打破刚才的约束了,所以删除会报错
若想删除关联的表,只能先删除子表,再删父表
2.表的设计
根据实际的需求场景,明确当前要创建几个表,每个表啥样子,这些表之间是否存在一定联系
一般来说,每个实体都需要安排一个表,表的列就对应到实体的各个属性
- 三大范式
2.1一对一
一个学生只能拥有***一个***账号
一个账号只能被***一个***学生拥有
2.2一对多
一个学生只能在***一个***班级中
一个班级可以包括***多个***学生
2.3多对多
一个学生可以选择***多门***课程
一门课程也可以包含***多个***学生
3.新增
把查询语句的查询结果作为插入的数值
语法:
insert into 表名 select * from 表名;
- 例:设计一张用户表,把已有的学生数据复制进来
mysql> insert into test_user(name) select name from student1;
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
-- 我们可以看到,学生姓名已经被成功的复制进来
mysql> select * from test_user;
+----+------+------+
| id | name | age |
+----+------+------+
| 1 | qqq | NULL |
| 2 | aaa | NULL |
| 3 | bbb | NULL |
| 4 | ccc | NULL |
| 5 | ddd | NULL |
| 6 | eee | NULL |
+----+------+------+
6 rows in set (0.00 sec)
4.查询
4.1聚合查询
表达式查询是针对列和列之间进行运算的,
聚合查询是相当于行和行之间进行运算的。
4.1.1聚合函数
SQL中提供了聚合函数,常见的统计总数,计算平均值等操作,可以使用聚合函数来实现,以下是常见的聚合函数:
函数 | 说明 |
---|---|
COUNT(expr) | 返回查询到的数据的数量,查询出来结果是集的行数 |
SUM(expr) | 返回查询到的数据的总和,只能针对数字,把这一列的若干行求和,算术运算 |
AVG(expr) | 返回查询到的数据的平均值 |
MAX(expr) | 返回查询到的数据的最大值 |
MIN(expr) | 返回查询到的数据的最小值 |
COUNT
-- 插入测试数据
mysql> insert into test_user (name) values('张三'),('李四'),('王五'),('赵六');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
-- 查询(用*查询不可进行去重,NULL也算进去)
mysql> select count(*) from test_user;
+----------+
| count(*) |
+----------+
| 4 |
+----------+
1 row in set (0.00 sec)
mysql> select count(0) from test_user;
+----------+
| count(0) |
+----------+
| 4 |
+----------+
1 row in set (0.01 sec)
-- 再插入几组年龄数据,姓名为空
mysql> insert into test_user (age) values(10),(12),(13);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
-- 我们先查询一下
mysql> select * from test_user;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 8 | 张三 | NULL |
| 9 | 李四 | NULL |
| 10 | 王五 | NULL |
| 11 | 赵六 | NULL |
| 12 | NULL | 10 |
| 13 | NULL | 12 |
| 14 | NULL | 13 |
+----+--------+------+
7 rows in set (0.00 sec)
-- 统计班级收集的年龄信息有多少个,年龄为NULL不会计入结果,也可进行去重
mysql> select count(age) from test_user;
+------------+
| count(age) |
+------------+
| 3 |
+------------+
1 row in set (0.00 sec)
SUM
mysql> select * from exam_result;
+------+-----------+---------+------+---------+
| id | name | chinese | math | english |
+------+-----------+---------+------+---------+
| 1 | 唐三藏 | 67.0 | 98.0 | 56.0 |
| 2 | 孙悟空 | 87.5 | 78.0 | 77.0 |
| 3 | 猪悟能 | 88.0 | 98.5 | 90.0 |
| 4 | 曹孟德 | 82.0 | 84.0 | 67.0 |
| 5 | 刘玄德 | 55.5 | 85.0 | 45.0 |
| 6 | 孙权 | 70.0 | 73.0 | 78.5 |
| 7 | 宋公明 | 75.0 | 65.0 | 30.0 |
+------+-----------+---------+------+---------+
7 rows in set (0.00 sec)
mysql> select sum(chinese) from exam_result;
+--------------+
| sum(chinese) |
+--------------+
| 525.0 |
+--------------+
1 row in set (0.00 sec)
sum函数中也可以使用表达式,先把对应列相加,得到的临时表再把这个临时表的结果进行相加,举例如下
mysql> select sum(chinese + math) from exam_result;
+---------------------+
| sum(chinese + math) |
+---------------------+
| 1106.5 |
+---------------------+
1 row in set (0.00 sec)
AVG
mysql> select avg(chinese+english+ math) as 平均总分 from exam_result;
+--------------+
| 平均总分 |
+--------------+
| 221.42857 |
+--------------+
1 row in set (0.00 sec)
MAX
mysql> select max(english) as 英语最高分 from exam_result;
+-----------------+
| 英语最高分 |
+-----------------+
| 90.0 |
+-----------------+
1 row in set (0.00 sec)
MIN
mysql> select min(math) as 数学最低分 from exam_result;
+-----------------+
| 数学最低分 |
+-----------------+
| 65.0 |
+-----------------+
1 row in set (0.00 sec)
4.1.2GROUP BY 子句
针对指定列进行分组,把这一列中值相同的行,分到一组中,然后得到若干个组,针对这些组分别使用聚合函数
语法
select column1,sum(column2)…… from table group by column1,column3;
- 例:准备测试表和数据
mysql> insert into emp(name, role, salary) values
-> ('马云','服务员', 1000.20),
-> ('马化腾','游戏陪玩', 2000.99),
-> ('孙悟空','游戏角色', 999.11),
-> ('猪无能','游戏角色', 333.5),
-> ('沙和尚','游戏角色', 700.33),
-> ('隔壁老王','董事长', 12000.66);
Query OK, 6 rows affected (0.01 sec)
Records: 6 Duplicates: 0 Warnings: 0
+----+--------------+--------------+----------+
| id | name | role | salary |
+----+--------------+--------------+----------+
| 1 | 马云 | 服务员 | 1000.20 |
| 2 | 马化腾 | 游戏陪玩 | 2000.99 |
| 3 | 孙悟空 | 游戏角色 | 999.11 |
| 4 | 猪无能 | 游戏角色 | 333.50 |
| 5 | 沙和尚 | 游戏角色 | 700.33 |
| 6 | 隔壁老王 | 董事长 | 12000.66 |
+----+--------------+--------------+----------+
6 rows in set (0.00 sec)
查询每个角色的最高工资、最低工资和平均工资
mysql> select role,max(salary),min(salary),avg(salary) from emp group by role;
+--------------+-------------+-------------+--------------+
| role | max(salary) | min(salary) | avg(salary) |
+--------------+-------------+-------------+--------------+
| 服务员 | 1000.20 | 1000.20 | 1000.200000 |
| 游戏角色 | 999.11 | 333.50 | 677.646667 |
| 游戏陪玩 | 2000.99 | 2000.99 | 2000.990000 |
| 董事长 | 12000.66 | 12000.66 | 12000.660000 |
+--------------+-------------+-------------+--------------+
4 rows in set (0.01 sec)
由于role这一列是group by指定的列,每一组的所有记录的role一定是相同的
如果分组之后不使用聚合函数,此时的结果就是查询出每一组中的某个代表数据,往往要搭配聚合函数使用,否则这里的查询结果就是没有意义的
- 在group by中,可以一个SQL同时完成这两个类的筛选
注意:可搭配条件需要区分清楚,该条件是分组之前的条件还是分组之后的条件
分组之前:直接使用where即可,where子句一般写在group by前
分组之后:查询每个岗位的平均薪资,但是排除平均薪资超过2w的结果,须使用下列的HAVING描述条件
4.1.3HAVING
GROUP BY子句进行分组之后,需要对分组结果再进行条件过滤时,不能使用where语句,而需要用HAVING
having语句一般写在group by 的后面
- 显示平均工资低于1500的角色和他的平均工资
mysql> select role,max(salary),min(salary),avg(salary) from emp group by role having avg(salary)<1500;
+--------------+-------------+-------------+-------------+
| role | max(salary) | min(salary) | avg(salary) |
+--------------+-------------+-------------+-------------+
| 服务员 | 1000.20 | 1000.20 | 1000.200000 |
| 游戏角色 | 999.11 | 333.50 | 677.646667 |
+--------------+-------------+-------------+-------------+
2 rows in set (0.00 sec)
4.2联合查询
(面试大概率考,但是实际开发中,而是要非常限制的使用,有时候使用起来很爽,但又不能广泛而不加节制的使用)
- 关键思路:理解笛卡尔积的工作原理
笛卡尔积:通过排列组合的方式得到一张更大的表,笛卡尔积的行数(列数)是这两个表的行数相加(列数相加),如果仔细观察可以看到其中有些数据是非法的(不符合实际情况,无意义),进行多表查询时,需要把有意义的数据筛选出来,无意义的数据过滤掉
4.2.1内连接
语法:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件
- 例:查询许仙同学的成绩
步骤:
- 先把两个表进行笛卡尔积
mysql> select * from student,score ;
- 加上连接条件,筛选出有效数据
mysql> select * from student,score where student.id = score.student_id;
- 结合需求添加条件,针对结果进行筛选
mysql> select * from student,score where student.id = score.student_id and student.name = '许仙';
+----+------+--------+---------------+------------+----+-------+------------+-----------+
| id | sn | name | qq_mail | classes_id | id | score | student_id | course_id |
+----+------+--------+---------------+------------+----+-------+------------+-----------+
| 4 | 31 | 许仙 | xuxian@qq.com | 1 | 10 | 67.0 | 4 | 1 |
| 4 | 31 | 许仙 | xuxian@qq.com | 1 | 11 | 23.0 | 4 | 3 |
| 4 | 31 | 许仙 | xuxian@qq.com | 1 | 12 | 56.0 | 4 | 5 |
| 4 | 31 | 许仙 | xuxian@qq.com | 1 | 13 | 72.0 | 4 | 6 |
+----+------+--------+---------------+------------+----+-------+------------+-----------+
4 rows in set (0.00 sec)
- 针对查询到的列进行精简
mysql> select student.name,score.score course from student,score where student.id = score.student_id and name = '许仙';
+--------+--------+
| name | course |
+--------+--------+
| 许仙 | 67.0 |
| 许仙 | 23.0 |
| 许仙 | 56.0 |
| 许仙 | 72.0 |
+--------+--------+
4 rows in set (0.00 sec)
- 例:查询所有同学的总成绩,及同学的个人信息
此时同学的成绩是按照行来组织的,此处就是多行数据进行加和,聚合函数还需按同学进行分组
- 先进行笛卡尔积
mysql> select * from student,score where student.id = score.student_id;
- 指定连接条件
mysql> select * from student,score where student.id = score.student_id;
- 先精简列
mysql> select student.name,sum(score.score) from student,score where student.id = score.student_id;
- 针对上述结果进行group by聚合查询
mysql> select student.name,sum(score.score) from student,score where student.id = score.student_id group by name;
+-----------------+------------------+
| name | sum(score.score) |
+-----------------+------------------+
| tellme | 172.0 |
| 不想毕业 | 118.0 |
| 好好说话 | 178.0 |
| 白素贞 | 200.0 |
| 菩提老祖 | 119.5 |
| 许仙 | 218.0 |
| 黑旋风李逵 | 300.0 |
+-----------------+------------------+
7 rows in set (0.01 sec)
- 例:查询所有同学的成绩以及个人信息
列出每个同学,每门课程的的课程名字和分数
- 先进行笛卡尔积
mysql> select * from student,score,course;
- 指定连接条件筛选数据
mysql> select * from student,score,course where student.id = score.student_id and course.id = score.course_id;
- 进行列的精简
mysql> select student.name,course.name,score.score from student,score,course where student.id = score.student_id and course.id = score.course_id;
+-----------------+--------------------+-------+
| name | name | score |
+-----------------+--------------------+-------+
| 黑旋风李逵 | Java | 70.5 |
| 菩提老祖 | Java | 60.0 |
| 白素贞 | Java | 33.0 |
| 许仙 | Java | 67.0 |
| 不想毕业 | Java | 81.0 |
| 好好说话 | 中国传统文化 | 56.0 |
| tellme | 中国传统文化 | 80.0 |
| 黑旋风李逵 | 计算机原理 | 98.5 |
| 白素贞 | 计算机原理 | 68.0 |
| 许仙 | 计算机原理 | 23.0 |
| 好好说话 | 语文 | 43.0 |
| 黑旋风李逵 | 高阶数学 | 33.0 |
| 菩提老祖 | 高阶数学 | 59.5 |
| 白素贞 | 高阶数学 | 99.0 |
| 许仙 | 高阶数学 | 56.0 |
| 不想毕业 | 高阶数学 | 37.0 |
| 黑旋风李逵 | 英文 | 98.0 |
| 许仙 | 英文 | 72.0 |
| 好好说话 | 英文 | 79.0 |
| tellme | 英文 | 92.0 |
+-----------------+--------------------+-------+
20 rows in set (0.00 sec)
笛卡尔积的缺点:要提前考虑好表的数量,一旦表数量大或数目多,笛卡尔积大,如果对大表进行笛卡尔积,会产生大量临时结果,耗费时间,如果多表查询的数目非常多,SQL复杂,可读性差
4.2.2外连接
如果两个表里的记录都是存在对应关系,内外连接的结果一定是一致的,如果不存在对应关系,内外链接就会出现差别
外连接分为左外连接和右外连接,如果联合查询,左侧的表完全显示我们就说是左外连接,右侧的表完全显示我们就说是右外连接
左外连接就是以左侧的表为基准,保证左侧的表的每个数据都会在最终的结果里,如果在右侧表中不存在,对应的列就填成NULL
右外连接就是以右侧的表为基准,保证右侧的表的每个数据都会在最终的结果里,如果在右侧表中不存在,对应的列就填成NULL
语法:
-- 左外连接,表1完全显示
select 字段 from 表名1 left join 表名2 on 连接条件
-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件
- 例:查询所有同学的成绩以及个人信息,如果同学没有成绩,也需要表示
-- “老外学中文”同学没有考试成绩也显示出来了
-- 左外连接
mysql> select * from student stu left join score sco on stu.id = sco.student_id;
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
| id | sn | name | qq_mail | classes_id | id | score | student_id | course_id |
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
| 1 | 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 | 1 | 70.5 | 1 | 1 |
| 1 | 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 | 2 | 98.5 | 1 | 3 |
| 1 | 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 | 3 | 33.0 | 1 | 5 |
| 1 | 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 | 4 | 98.0 | 1 | 6 |
| 2 | 835 | 菩提老祖 | NULL | 1 | 5 | 60.0 | 2 | 1 |
| 2 | 835 | 菩提老祖 | NULL | 1 | 6 | 59.5 | 2 | 5 |
| 3 | 391 | 白素贞 | NULL | 1 | 7 | 33.0 | 3 | 1 |
| 3 | 391 | 白素贞 | NULL | 1 | 8 | 68.0 | 3 | 3 |
| 3 | 391 | 白素贞 | NULL | 1 | 9 | 99.0 | 3 | 5 |
| 4 | 31 | 许仙 | xuxian@qq.com | 1 | 10 | 67.0 | 4 | 1 |
| 4 | 31 | 许仙 | xuxian@qq.com | 1 | 11 | 23.0 | 4 | 3 |
| 4 | 31 | 许仙 | xuxian@qq.com | 1 | 12 | 56.0 | 4 | 5 |
| 4 | 31 | 许仙 | xuxian@qq.com | 1 | 13 | 72.0 | 4 | 6 |
| 5 | 54 | 不想毕业 | NULL | 1 | 14 | 81.0 | 5 | 1 |
| 5 | 54 | 不想毕业 | NULL | 1 | 15 | 37.0 | 5 | 5 |
| 6 | 51234 | 好好说话 | say@qq.com | 2 | 16 | 56.0 | 6 | 2 |
| 6 | 51234 | 好好说话 | say@qq.com | 2 | 17 | 43.0 | 6 | 4 |
| 6 | 51234 | 好好说话 | say@qq.com | 2 | 18 | 79.0 | 6 | 6 |
| 7 | 83223 | tellme | NULL | 2 | 19 | 80.0 | 7 | 2 |
| 7 | 83223 | tellme | NULL | 2 | 20 | 92.0 | 7 | 6 |
| 8 | 9527 | 老外学中文 | foreigner@qq.com | 2 | NULL | NULL | NULL | NULL |
+----+-------+-----------------+------------------+------------+------+-------+------------+-----------+
21 rows in set (0.00 sec)
4.2.3自连接
自己和自己进行笛卡尔积,有时需要进行行和行的比较,而SQL只能进行行和列进行比较,此时就可以使用自连接,把行关系转成列关系
- 例:查询成绩表中计算机原理成绩比Java成绩好的信息
mysql> select s1.student_id,s1.score,s2.score from score as s1,score as s2 where s1.student_id = s2.student_id and s1.course_id = 3 and s2.course_id = 1 and s1.score > s2.score;
+------------+-------+-------+
| student_id | score | score |
+------------+-------+-------+
| 1 | 98.5 | 70.5 |
| 3 | 68.0 | 33.0 |
+------------+-------+-------+
2 rows in set (0.01 sec)
4.2.4子查询
子查询的本质是套娃,把多个简单的SQL拼接成一个复杂的SQL,违背了一贯的变成原则
- 例:查询与“不想毕业”的同班同学
mysql> select * from student where classes_id = (select classes_id from student where name = '不想毕业');
+----+------+-----------------+-----------------+------------+
| id | sn | name | qq_mail | classes_id |
+----+------+-----------------+-----------------+------------+
| 1 | 9982 | 黑旋风李逵 | xuanfeng@qq.com | 1 |
| 2 | 835 | 菩提老祖 | NULL | 1 |
| 3 | 391 | 白素贞 | NULL | 1 |
| 4 | 31 | 许仙 | xuxian@qq.com | 1 |
| 5 | 54 | 不想毕业 | NULL | 1 |
+----+------+-----------------+-----------------+------------+
5 rows in set (0.00 sec)
4.2.5合并查询
把多个SQL的查询结果集合合并到一起
在实际应用中,为了合并多个select的执行结果,可以使用操作符union,union all。使用这两个时,前后查询的结果集中,字段需要一致
union
:该操作符用于取得两个结果集的并集,当使用该操作符时,会自动去掉结果集中的重复行
- 例:查询id小于3,或者名字为“英文”的课程
mysql> select * from course where id < 3 union select * from course where name = '英文';
+----+--------------------+
| id | name |
+----+--------------------+
| 1 | Java |
| 2 | 中国传统文化 |
| 6 | 英文 |
+----+--------------------+
3 rows in set (0.00 sec)
合并的两个SQL的结果集的列的个数和类型需要一致,union允许把两个不同的表查询结果合并到一起,并进行去重,若不想去重则使用union all
union all
:不会去掉结果集中的重复行
- 例:查询id小于3,或者名字为“Java”的课程
mysql> select * from course where id < 3 union all select * from course where name = '英文';
+----+--------------------+
| id | name |
+----+--------------------+
| 1 | Java |
| 2 | 中国传统文化 |
| 6 | 英文 |
+----+--------------------+
3 rows in set (0.00 sec)