目录
- 一、数据库约束
-
- 1.1 NULL约束
- 1.2 UNIQUE:唯一约束
- 1.3 DEFAULT:默认值约束
- 1.4 PRIMARY KEY:主键约束
- 1.5 FOREIGN KEY:外键约束
- 1.6 CHECK约束
- 二、表的设计
-
- 实体之间的关系
-
- 一对一
- 一对多
- 多对多
- 三、 新增
- 四、查询
-
- 4.1 聚合查询
-
- 4.1.1聚合函数
- 4.1.2 分组操作group by
- 4.1.3 having 过滤
- 4.2 联合查询
-
- 4.2.1 内连接
- 4.2.2 外连接
- 4.2.3 自连接
- 4.2.4 子查询
- 4.2.5 合并查询
一、数据库约束 约束就是数据库在使用的时候,对于里面能够存的数据提出的要求和限制.
1.1 NULL约束
not null
-指示某列不能存储NULL值.
文章图片
给
id
这一列设为not null
之后,上图中紫色框里的值就变成NO
了.如果尝试往这里插入空值,就会直接报错:
文章图片
注意:NOT NULL是可以给任意个列来进行设置,不仅仅是这一个列.
1.2 UNIQUE:唯一约束
unique
-保证某列的每行必须有唯一的值,即数据唯一.
文章图片
文章图片
1.3 DEFAULT:默认值约束
default
-规定没有给列赋值时的默认值,即约定一个默认值.
文章图片
添加名字的默认值约束为匿名:
文章图片
如果未修改只添加id,name处会显示为null,添加默认值约束之后,此时name处显示为"匿名".
文章图片
1.4 PRIMARY KEY:主键约束
primary key
-NOT NULL和UNIQUE的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。
主键约束是最常使用的一个约束,相当于数据的唯一身份标识,类似于身份证号码/手机号码.
对于一个表来说,只能有一个列被指定为主键.
文章图片
关于主键,典型的用法,就是直接使用1,2,3, 4整数递增的方式来进行表示MySQL里面对于这种递增的主键,是有内置支持的,称为"自增主键".
对于整数类型的主键,常配搭自增长auto_increment
来使用。插入数据对应字段不给值时,使用最大值+1
.
create table student(ia int primary key auto_increment,name varchar(50));
文章图片
当设定好自增主键之后,此时插入的记录,就可以不指定自增主键的值了(直接使用
null
来表示),交给mysql
自行分配即可.文章图片
自增主键也可以手动指定id ,一旦指定过之后,后续新插入的数据就都是从8之后来排了.2-8之间的就用不了.再次插入的时候就从8之后开始计数.
文章图片
1.5 FOREIGN KEY:外键约束
foreign key
-保证一个表中的数据匹配另一个表中的值的参照完整性。
外键用于关联其他表的主键或唯一键.
foreign key (字段名) references (主表)列;
外键约束,针对两张表,进行了关联。
在这里创建两张表:
学生表(id,name,classId)
班级表(classId,name)
学生表依赖了班级表,就把学生表称为"子表",班级表称为"父表".
- 首先创建班级表:
文章图片
- 然后创建学生表:
create table student(studentId int primary key auto_increment,name varchar(30),classId int,foreign key(classId) references class(classId));
references
:叫作(表示依赖关系,当前这个表的classld
列就得引用自/依赖于class
表的classld
这一列)class(classId)
:引用的父表的名字叫做class
表,引用的父表的列是classld
这一列。文章图片
在创建好表之后就可以往
student
学生表里面插入数据,在插入记录之前, mysql
会先拿着这个classld
去class
表里查一下,看看是否存在,存在才能插入成功。文章图片
因为班级
classId
里面并没有4班,所以下面那条插入不成功。不仅仅是新增的时候要考虑到外键约束,新增成功的数据如果进行修改,也一样是会存在问题。因为并没有这个班级存在。
文章图片
student
表中的classld
是可以重复的,只要是在class
表中存在即可。文章图片
外键约束,同样也在约束着父表.当父表中的某个记录被子表中依赖着的时候,此时尝试进行删除或者修改,都会失败。
文章图片
如果有的
classId
没有在student
表中被依赖到,则就可以进行删除。外键约束的工作原理:
在子表中插入新的记录的时候,就会先根据对应的值,在父表中先查询,查询到之后,才能够执行后续的插入。
这里的查询操作,可能是一个成本较高的操作(比较耗时),外键约束其实要求,父表中被依赖的这一列,必须要有索引,有了索引就能大大的提高查询速度。
1.6 CHECK约束
check
-保证列中的值符合指定的条件。对于MySQL
数据库,对CHECK
子句进行分析,但是忽略CHECK
子句。
drop table if exists test_user;
create table test_user (
id int,
name varchar(20),
sex varchar(1),
check (sex ='男' or sex='女')
);
二、表的设计 如何设计数据库,如何设计表?
一个典型的通用的办法:先找出这个场景中涉及到的“实体",然后再来分析"实体之间的关系"。
实体之间的关系 一对一
文章图片
一对多
1.5中学生和班级的例子。
文章图片
多对多
文章图片
文章图片
可以使用一个关联表来表示两个实体之间的关系。
文章图片
上表中:学号为1的同学,选了课程编号为1的课程.
课程编号为1的课程,包含了一个学号为1的同学.
张三选了语文课.语文课上有张三.
学号为1的同学,选了课程编号为2的课程.
张三选了数学课.数学课上有张三.
三、 新增 和查询结合在一起的新增操作。把从上一个表中的查询结果,作为下一个表要插入的数据。
首先先创建一个A表:
文章图片
然后将A表的记录插入到B表中:
文章图片
在红框中的这个语句中,就会先执行查找.针对查找到的每个结果,都执行插入操作,插入到B中.
我们需要保证,从A中查询出来的结果的列数和类型,和B表匹配.
如果B表的列的顺序和A表不匹配,只要保证A的查询结果的列的顺序和B对应即可。如:
insert into B select id,name from A;
另外,还可以给后面的select 指定一些其他的条件/排序/limit/去重…
插入的实际就是select执行结果的临时表。要保证插入之后数据是合理的。
四、查询 4.1 聚合查询 把多个行的数据进行了关联操作。
4.1.1聚合函数
函数 | 说明 |
---|---|
count([distinct]) expr | 查询到的数据的数量,null值不会记录到count中 |
sum([distinct] expr) | 返回查询到的数据的总和,不是数字没有意义 |
avg([distinct] expr) | 返回查询到的数据的平均值,不是数字没有意义 |
max([distinct] expr) | 返回查询到的数据的最大值,不是数字没有意义 |
min([distinct] expr) | 返回查询到的数据的最小值,不是数字没有意义 |
文章图片
count
文章图片
就相当于是针对select * from exam_result;
的结果集合进行计算行数.
count
这里的参数不一定非要写做*
也可以指定某个列,NULL
这样的值不会记录到count
中。
文章图片
- sum
sum
进行求和. (相对于excel里的求和),把这一列的若干行,进行相加。文章图片
sum
这个操作只能针对数字进行运算,不能针对字符串来进行。- avg
文章图片
计算
avg
的时候, NULL
这样的记录是不计入其中的,不会影响到平均值的结果。文章图片
- max
文章图片
- min
where
字句来使用,可以基于条件进行筛选,把筛选结果,在进行聚合。返回 > 70 分以上的数学最低分:
文章图片
4.1.2 分组操作group by
SELECT
中使用 GROUP BY
子句可以对指定列进行分组查询。需要满足:使用 GROUP BY
进行分组查询时,SELECT
指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT
中则必须包含在聚合函数中.根据行的值,对数据进行分组.把值相同的行都归为一组.
文章图片
文章图片
查询每个角色的最高工资、最低工资和平均工资:
文章图片
一个
sql
的执行过程,具体的执行顺序,和书写的顺序并不完全一致。这里先执行group by
,把这里的查询结果进行分组,再根据分组,分别来执行每个组的聚合函数。4.1.3 having 过滤
group by
子句进行分组以后,需要对分组结果再进行条件过滤时,就需要使用having
。group by
是可以使用where
.只不过 where
是在分组之前执行.如果要对分组之后的结果进行条件筛选,就需要使用having 。把沙和尚去掉之后,在按照角色进行分类,求平均值:
文章图片
求每种角色,平均薪资,只保留平均薪资1w以下:
文章图片
4.2 联合查询 实际开发中往往数据来自不同的表,所以需要多表联合查询。即把多个表的记录往一起合并,一起进行查询。联合查询又叫做多表查询。
多表查询是对多张表的数据取笛卡尔积:笛卡尔积是针对任意两张表之间进行运算的。
笛卡尔积的运算过程:
先拿第一张表的第一条记录和第二张表的每个记录分别组合,得到一组新的记录。继续那第一张表的第二条记录,重复刚才的记录。直到第一张表的记录被组合完为止。
如表a和表b:
文章图片
进行笛卡尔积之后:
a | aa | 1 | 11 |
---|---|---|---|
a | aa | 2 | 22 |
b | bb | 1 | 11 |
b | bb | 2 | 22 |
a的列数+b的列数
.笛卡尔积的行数就是a的行数*b的行数
.在SQL中进行笛卡尔积,最简单的做法,就是直接select, from后面跟上多个表名,表名之间使用逗号分割。
例:
select * from student,class;
笛卡尔积是一个单纯无脑的排列组合,这里的组合结果不一定都是有意义的数据,这里可以使用
where
进行条件筛选,保留我们需要的记录。select * from student,class where student.classId = class.classId;
创建四张表并向表中加入数据:
drop table if exists classes;
drop table if exists student;
drop table if exists course;
drop table if exists score;
create table classes (id int primary key auto_increment, name varchar(20), `desc` varchar(100));
create table student (id int primary key auto_increment, sn varchar(20),name varchar(20), qq_mail varchar(20) ,
classes_id int);
create table course(id int primary key auto_increment, name varchar(20));
create table score(score decimal(3, 1), student_id int, course_id int);
insert into classes(name, `desc`) values
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');
insert into student(sn, name, qq_mail, classes_id) values
('09982','黑旋风李逵','xuanfeng@qq.com',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','xuxian@qq.com',1),
('00054','不想毕业',null,1),
('51234','好好说话','say@qq.com',2),
('83223','tellme',null,2),
('09527','老外学中文','foreigner@qq.com',2);
insert into course(name) values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');
insert into score(score, student_id, course_id) values
-- 黑旋风李逵
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
-- 菩提老祖
(60, 2, 1),(59.5, 2, 5),
-- 白素贞
(33, 3, 1),(68, 3, 3),(99, 3, 5),
-- 许仙
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
-- 不想毕业
(81, 5, 1),(37, 5, 5),
-- 好好说话
(56, 6, 2),(43, 6, 4),(79, 6, 6),
-- tellme
(80, 7, 2),(92, 7, 6);
查询每张表:
文章图片
文章图片
4.2.1 内连接
语法:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;
(1)查询许仙的成绩:
select student.name,score.score from student,score where student.id = score.student_id and student.name = '许仙';
文章图片
select student.name,score.score from student join score on student.id = score.student_id and student.name = '许仙';
文章图片
(2)查询所有同学的总成绩,及同学的个人信息:
select student.name,sum(score.score) from student,score where student.id = score.student_id group by student.id;
文章图片
select student.name,sum(score.score) from student join score on student.id = score.student_id group by student.id;
文章图片
(3)查询所有同学的成绩,及同学的个人信息:
select student.name,course.name,score.score from student,course,score where score.student_id = student.id and score.course_id = course.id;
文章图片
select student.name,course.name,score.score from student join score on score.student_id = student.id join course on score.course_id = course.id;
文章图片
4.2.2 外连接
外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接。
语法:
--左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;
例:创建两张表学生表和分数表:
文章图片
文章图片
内连接里的记录就只是包含两个表中同时拥有的记录:
文章图片
左外连接就是以左侧表为主.左侧表中的每个记录都在左外连接中有体现.
文章图片
右外连接就是以右侧表为主.右侧表的每个记录都在结果中有体现。
文章图片
4.2.3 自连接
自连接是指在同一张表连接自身进行查询。就是把自己和自己进行笛卡尔积。
自连接的本质:是把行和行之间的比较条件,转换成列和列。
SQL指定条件,都是按照列和列之间进行指定的。
自连接的关键就是把行转换成列。
如:显示所有“计算机原理”成绩比“Java”成绩高的成绩信息。
文章图片
从上表中可看出Java和计算机原理的课程Id分别为1和3。
文章图片
此时,我们可以看出它是行和行之间的比较,要解决上述问题,就要将它转换为列与列之间的比较,这是,就可以用到自连接。
在进行自连接之后,会出现很多无效数据,为了能够更好的进行比较,再加上一些筛选条件,比如,就让s1的课程id只保留3的记录,就让s2的课程id只保留1的记录。
文章图片
将目录进行简化:
文章图片
4.2.4 子查询
子查询是指嵌入在其他
sql
语句中的select
语句,也叫嵌套查询。子查询就是把拆分好的代码给合并成一个。
- 单行查询:返回一行记录的子查询
先根据该同学的名字找到其班级Id
文章图片
文章图片
找到“不想毕业”同学的班级id为1,则他就是1班的同学。然后再通过其班级id找到他们班上都有哪些同学:
文章图片
也可以将这两行
sql
字句写成合并的sql
:文章图片
- 多行子查询:返回多行记录的子查询
=
,可能需要用到in
这样的一些操作。如:查询“语文”或“英文”课程的成绩信息
先根据语文和英语找到对应的课程id,再根据课程id找到对用的成绩信息:
文章图片
文章图片
同样,也可以把这两条sql合并成一条sql:
文章图片
4.2.5 合并查询
在实际应用中,为了合并多个
select
的执行结果,可以使用集合操作符 union
,union all
。使用UNION和UNION ALL时,前后查询的结果集中,字段需要一致(通过union
把两个sql
的查询结果给合并到一起,合并的前提是两个sql
查询的列得是对应的)。- union
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。
如:查询id小于3,或者名字为“英文”的课程:
文章图片
此处的union不一定针对同一张表。
上面的写法也可以用or来代替:
文章图片
union操作会自动的进行去重,union all是不会去重。 - union all
该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。
如:查询id小于3,或者名字为“Java”的课程:
文章图片
推荐阅读
- SQL|python操作mysql插入数据
- ClickHouse
- ui|云计算会杀死开源吗()
- 国产化浪潮下TiDB解决的痛点问题
- mysql|mysql管理性能状态查看命令
- 数据库|MySQL单表数据量过千万,采坑优化记录,完美解决方案
- MySQL|10分钟必懂-深入理解MySQL隔离级别与锁机制
- MySQL|6000字总结MySQL最基础的增删查改命令
- MySQL|MySQL数据库:入门必备基础更新了哦~~~