第一章:MySQL | 数据库的管理和操作(基本介绍)
第二章:MySQL | 数据库的基本操作和表的基本操作
第三章:MySQL | 数据库的表的增删改查
第四章:MySQL | 数据库的表的增删改查【进阶】
前言:
创建表时,可以指定某列不为空:
create table student(id int,name varchar(20));
insert into student values(null,null);
create table student (id int not null, name varchar(20) not null);
插入/修改数据的时候,会先查询,先看看数据是否已经存在,如果不存在,就能插入/修改成功,如果存在,则插入/修改失败!
可以看到数据已经插入了一次,就不能插入了
create table student (id int unique, name varchar(20));
insert into student (id) values(2);
create table student (id int,name varchar(20) default '无名氏');
create table student (id int primary key, name varchar(20));
insert into student values (1,'张三');
一个重要的问题:
create table student (id int primary key auto_increment, name varchar(20));
给自增主键插入数据的时候,可以手动指定一个值,也可以让mysql自己分配,如果让他自己分配,就在insert语句的时候,把id设为null即可
insert into student values(100,'赵六');
insert into student values (null,'七七');
create table class(class_id int primary key auto_increment, class_name varchar(20));
create table student(student_id int primary key auto_increment, name varchar(20),class_id int, foreign key (class_id) references class(class_id));
这里写的是不能新增或者修改子
这里我们插入点班级数据
insert into class values(null,'cls1'); insert into class values(null,'cls2'); insert into class values(null,'cls3');
insert into student values(null,'张三',1);
换句话说student表插入数据的时候,mysql先会做一件事,会拿着这个记录的class_id去class表中看看有没有~~
不仅是插入,修改也会有约束
update student set class_id = 10 where student_id = 1;
这个对于mysql5是不支持的,所以这里就先不讲了~~
设计表要求有一定的经验,才能理解~~
设计表,分两步走
很多时候,每个实体就需要对应一张表来进行表示~~
实体之间的关系。主要有三种(严格来说是四种)
一对一
一对多
多对多
把查询和新增联合起来
create table student (id int ,name varchar(20)); create table student2 (id int ,name varchar(20)); insert into student values(1,'张三'),(2,'李四'),(3,'王五');
insert into student2 select * from student;
聚合函数,这些是sql提供的库函数
select count(*) from student;
再来看一下下一个sum
CREATE TABLE exam_result ( id INT, name VARCHAR(20), chinese DECIMAL(3,1), math DECIMAL(3,1), english DECIMAL(3,1) );
INSERT INTO exam_result (id,name, chinese, math, english) VALUES (1,'唐三藏', 67, 98, 56), (2,'孙悟空', 87.5, 78, 77), (3,'猪悟能', 88, 98.5, 90), (4,'曹孟德', 82, 84, 67), (5,'刘玄德', 55.5, 85, 45), (6,'孙权', 70, 73, 78.5), (7,'宋公明', 75, 65, 30);
select sum(chinese) from exam_result;
insert into exam_result values (8,'如来佛祖',null,null,null); select sum(chinese) from exam_result;
select sum(name) from exam_result;
show warnings;
不光sum如此,后面的这几个都是一样的
我们再来看avg,这个查看平均分的
select avg(chinese) from exam_result;
聚合函数还能搭配表达式使用,比如求总分的平均分
select avg(chinese + math + english) as avg_total from exam_result;
select max(chinese),min(chinese) from exam_result;
好了,聚合函数就这些了~~
上面这些聚合函数,默认都是针对这个表里的所有类进行了聚合
有时候我们还需要分组聚合(按照指定的字段,把记录分成若干组,每一组分别使用聚合函数)
比如说这里我们创建一个员工表
create table emp (id int,name varchar(20), role varchar(20),salary int);
insert into emp values(1,'孙悟空','讲师',10000); insert into emp values(2,'猪悟能','讲师',11000); insert into emp values(3,'沙悟净','讲师',12000); insert into emp values(4,'刘玄德','学管师',10000); insert into emp values(5,'曹孟德','学管师',9000); insert into emp values(6,'如来佛祖','老板',100000); insert into emp values(7,'太上老君','老板',120000);
select role,avg(salary) from emp group by role;
比如求每个岗位的平均薪资,但是刨除孙悟空同学~~
select role,avg(salary) from emp where name != '孙悟空' group by role;
select role,avg(salary) from emp group by role having role != '老板';
select role,avg(salary) from emp where name != '孙悟空' group by role having role != '老板';
联合查询(多表查询)
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);
笛卡尔积
select * from student,score;
多表查询一般实现步骤
语法:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件; select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;
案例:
(1)查询“许仙”同学的 成绩
select sco.score from student stu inner join score sco on stu.id=sco.student_id and stu.name='许仙'; -- 或者 select sco.score from student stu, score sco where stu.id=sco.student_id and stu.name='许仙';
(2)查询所有同学的总成绩,及同学的个人信息:
-- 成绩表对学生表是多对1关系,查询总成绩是根据成绩表的同学id来进行分组的 SELECT stu.sn, stu.NAME, stu.qq_mail, sum( sco.score ) FROM student stu JOIN score sco ON stu.id = sco.student_id GROUP BY sco.student_id;
(3)查询所有同学的成绩,及同学的个人信息:
-- 查询出来的都是有成绩的同学,“老外学中文”同学 没有显示 select * from student stu join score sco on stu.id=sco.student_id; -- 学生表、成绩表、课程表3张表关联查询 SELECT stu.id, stu.sn, stu.NAME, stu.qq_mail, sco.score, sco.course_id, cou.NAME FROM student stu JOIN score sco ON stu.id = sco.student_id JOIN course cou ON sco.course_id = cou.id ORDER BY stu.id;
外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接。
语法:
-- 左外连接,表1完全显示 select 字段名 from 表名1 left join 表名2 on 连接条件; -- 右外连接,表2完全显示 select 字段 from 表名1 right join 表名2 on 连接条件;
案例:查询所有同学的成绩,及同学的个人信息,如果该同学没有成绩,也需要显示
-- “老外学中文”同学 没有考试成绩,也显示出来了 select * from student stu left join score sco on stu.id=sco.student_id; -- 对应的右外连接为: select * from score sco right join student stu on stu.id=sco.student_id; -- 学生表、成绩表、课程表3张表关联查询 SELECT stu.id, stu.sn, stu.NAME, stu.qq_mail, sco.score, sco.course_id, cou.NAME FROM student stu LEFT JOIN score sco ON stu.id = sco.student_id LEFT JOIN course cou ON sco.course_id = cou.id ORDER BY stu.id;
自连接是指在同一张表连接自身进行查询。
案例:
显示所有“计算机原理”成绩比“Java”成绩高的成绩信息
-- 先查询“计算机原理”和“Java”课程的id select id,name from course where name='Java' or name='计算机原理'; -- 再查询成绩表中,“计算机原理”成绩比“Java”成绩 好的信息 SELECT s1.* FROM score s1, score s2 WHERE s1.student_id = s2.student_id AND s1.score < s2.score AND s1.course_id = 1 AND s2.course_id = 3; -- 也可以使用join on 语句来进行自连接查询 SELECT s1.* FROM score s1 JOIN score s2 ON s1.student_id = s2.student_id AND s1.score < s2.score AND s1.course_id = 1 AND s2.course_id = 3;
以上查询只显示了成绩信息,并且是分布执行的。要显示学生及成绩信息,并在一条语句显示:
SELECT stu.*, s1.score Java, s2.score 计算机原理 FROM score s1 JOIN score s2 ON s1.student_id = s2.student_id JOIN student stu ON s1.student_id = stu.id JOIN course c1 ON s1.course_id = c1.id JOIN course c2 ON s2.course_id = c2.id AND s1.score < s2.score AND c1.NAME = 'Java' AND c2.NAME = '计算机原理';
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询
select * from student where classes_id=(select classes_id from student where name='不想毕业');
-- 使用IN select * from score where course_id in (select id from course where name='语文' or name='英文'); -- 使用 NOT IN select * from score where course_id not in (select id from course where name!='语文' and name!='英文');
可以使用多列包含:
-- 插入重复的分数:score, student_id, course_id列重复 insert into score(score, student_id, course_id) values -- 黑旋风李逵 (70.5, 1, 1),(98.5, 1, 3), -- 菩提老祖 (60, 2, 1); -- 查询重复的分数 SELECT * FROM score WHERE ( score, student_id, course_id ) IN ( SELECT score, student_id, course_id FROM score GROUP BY score, student_id, course_id HAVING count( 0 ) > 1 );
-- 使用 EXISTS select * from score sco where exists (select sco.id from course cou where (name='语文' or name='英文') and cou.id = sco.course_id); -- 使用 NOT EXISTS select * from score sco where not exists (select sco.id from course cou where (name!='语文' and name!='英文') and cou.id = sco.course_id);
在from子句中使用子查询:子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个
子查询当做一个临时表使用。
查询所有比“中文系2019级3班”平均分高的成绩信息:
-- 获取“中文系2019级3班”的平均分,将其看作临时表 SELECT avg( sco.score ) score FROM score sco JOIN student stu ON sco.student_id = stu.id JOIN classes cls ON stu.classes_id = cls.id WHERE cls.NAME = '中文系2019级3班';
查询成绩表中,比以上临时表平均分高的成绩:
SELECT * FROM score sco, ( SELECT avg( sco.score ) score FROM score sco JOIN student stu ON sco.student_id = stu.id JOIN classes cls ON stu.classes_id = cls.id WHERE cls.NAME = '中文系2019级3班' ) tmp WHERE sco.score > tmp.score;
在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all。使用UNION
和UNION ALL时,前后查询的结果集中,字段需要一致。
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。
案例:查询id小于3,或者名字为“英文”的课程:
select * from course where id<3 union select * from course where name='英文'; -- 或者使用or来实现 select * from course where id<3 or name='英文';
该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。
案例:查询id小于3,或者名字为“Java”的课程
-- 可以看到结果集中出现重复数据Java select * from course where id<3 union all select * from course where name='英文';
新增:
INSERT INTO table_name [(column [, column ...])] SELECT ...
select ... from 表1,表2 where 条件 -- inner可以缺省 select ... from 表1 join 表2 on 条件 where 其他条件
select ... from 表1 left/right join 表2 on 条件 where 其他条件
select ... from 表1,表1 where 条件 select ... from 表1 join 表1 on 条件
-- 单行子查询 select ... from 表1 where 字段1 = (select ... from ...); -- [NOT] IN select ... from 表1 where 字段1 in (select ... from ...); -- [NOT] EXISTS select ... from 表1 where exists (select ... from ... where 条件); -- 临时表:form子句中的子查询 select ... from 表1, (select ... from ...) as tmp where 条件
-- UNION:去除重复数据 select ... from ... where 条件 union select ... from ... where 条件 -- UNION ALL:不去重 select ... from ... where 条件 union all select ... from ... where 条件 -- 使用UNION和UNION ALL时,前后查询的结果集中,字段需要一致
好了,MySQL | 数据库的表的增删改查【进阶】就到这里了,希望看完有所收获!!!
如果觉得有用的话三连一下吧~~🌹🌹🌹