表的增删查改(进阶)—MySQL

文章目录

  • 1.数据库约束
    • 1.1 null约束
    • 1.2 unique:唯一约束
    • 1.3 default:默认值约束
    • 1.4 primary key:主键约束(非空且唯一)
    • 1.5 foreign key:外键约束
    • 1.6 check约束(MySQL没有实现)
  • 2.表的设计
    • 2.1数据库建立表关系
    • 2.2一对一关系
    • 2.3一对多关系
    • 2.4多对多关系
  • 3.插入数据
    • 3.1使用场景
  • 4.查询数据
    • 4.1聚合查询
      • 4.1.1聚合函数
      • 4.1.2 group by(分组)
      • 4.1.3having(分组后的过滤条件)
    • 4.2联合查询(多表查询,复合查询)
      • 4.2.1两个表的笛卡尔积
      • 4.2.2内连接
      • 4.2.3外连接
      • 4.2.4内连接和外连接的区别
      • 4.2.5自连接
      • 4.2.6子查询
      • 4.2.7合并查询

1.数据库约束

约束:按照一定的条件进行规范的做事,表定义的时候,某些字段保存的数据,需要按照一定的约束条件

1.1 null约束

(1)字段null:该字段可以为空
(2)字段not null:该字段不允许为空(如果插入数据的时候没插入或者插入null都会报错)
(3)不指定默认是允许为空

--非空约束
drop table if exists student;
create table student(
    id int not null,
    name varchar(20),
    sex bit,
    resume text,
    amount decimal(11,2),
    birthday datetime
);
insert into student(id,name) values (1,'张三');
-- 报错
insert into student(name) values ('张三');

表的增删查改(进阶)—MySQL_第1张图片

1.2 unique:唯一约束

表示某个字段,不能重复,null不进行unique唯一性校验,实际可以使用多个字段来建立unique唯一约束(该字段插入相同的值会报错)

-- 唯一约束
drop table if exists student;
create table student(
    id int not null,
    name varchar(20) unique,
    sex bit,
    resume text,
    amount decimal(11,2),
    birthday datetime
);
insert into student(id,name) values (1,'张三');
-- 报错,姓名不能重复
insert into student(id,name) values (2,'张三');

表的增删查改(进阶)—MySQL_第2张图片

1.3 default:默认值约束

(1)某个字段设置了default及默认值,插入的时候,该列不插入,就会插入默认值
(2)显示的插入数据,即使是null,默认值也不会生效

-- 默认值约束
drop table if exists student;
create table student(
    id int not null ,
    name varchar(20) default 'unkown',
    sex bit,
    resume text,
    amount decimal(11,2),
    birthday datetime
);
insert into student(id,name) values (1,'张三');
-- id 为2的学生姓名默认插入unknown
insert into student(id) values (2);

表的增删查改(进阶)—MySQL_第3张图片

1.4 primary key:主键约束(非空且唯一)

(1)primary key = not null
(2)主键一般就用于某张表,标识唯一的一条数据,主键约束也可以使用多个字段,也叫复合主键
(3)仅仅unique约束的字段,还可以保存多条null的数据,也不能标识唯一的数据
(4)主键字段,不插入,或者是插入重复,就会报错

-- 主键约束
drop table if exists student;
create table student(
    id int primary key,
    name varchar(20) default 'unkown',
    sex bit,
    resume text,
    amount decimal(11,2),
    birthday datetime
);
insert into student(id,name) values (1,'张三');
-- 重复报错
insert into student(id,name) values (1,'李四');
-- 不插入也报错
insert into student(name) values ('李四');

表的增删查改(进阶)—MySQL_第4张图片
(5)简单看,一张表,一般都需要设计一个主键
(6)如果使用整形主键,还可以结合auto_increment(这个是MySQL的关键字,不是标椎sql),表示从1开始,++自增

drop table if exists student;
create table student(
    id int primary key auto_increment,
    name varchar(20) default 'unkown',
    sex bit,
    resume text,
    amount decimal(11,2),
    birthday datetime
);
insert into student(id,name) values (1,'张三');
insert into student(name) values ('李四');
insert into student(name) values ('王五');

表的增删查改(进阶)—MySQL_第5张图片

1.5 foreign key:外键约束

(1)用于设计表和表之间的关系
(2)表1(主表:主键)——表2(从表:外键):建立表1和表2,一对多或一对一的关系

-- 学生表(主表)
drop table if exists student;
create table student(
    -- 学生表主键
    id int primary key auto_increment,
    name varchar(20) not null
);
-- 中间表:学生考试成绩表
drop table if exists exam_score;
create table exam_score(
    -- 学生考试成绩表主键
    id int primary key auto_increment,
    -- 学生表的主键作为中间表的外键
    student_id int,
    -- 建立主外键关系
    foreign key(student_id) references student(id),
);

1.6 check约束(MySQL没有实现)

drop table if exists student;
create table student (
   id int,
   name varchar(20),
   sex varchar(1),
   -- sex只能是男和女,插入其他的就会报错
   check (sex ='男' or sex='女')
);

2.表的设计

数据库的表设计就是建立一种对象模型

2.1数据库建立表关系

(1)语法上只有一中写法
表的增删查改(进阶)—MySQL_第6张图片
主表的主键关联从表的外键(实际上建立外键,不一定要使用主键来关联)
(2)写法
表的增删查改(进阶)—MySQL_第7张图片

2.2一对一关系

表的增删查改(进阶)—MySQL_第8张图片
(1)从实现上看,一张表也可以实现,但是效率不高(比如:比较频繁的获取人的姓名而不需要获取身份信息)
(2)设计两张表的目的:解耦:模型之间的解耦;效率:不经常使用的数据单独存储,效率比较高

2.3一对多关系

表的增删查改(进阶)—MySQL_第9张图片
一对多是有方向的,包含:
(1)班级到学生:一对多,一个班级多个学生
(2)学生到班级:一对一,一个学生一个班级

2.4多对多关系

(1)表设计的时候:两张主表建立多对多关系的时候,主表中没有外键体现;使用一张单独的中间表来表示两张主表的多对多关系,设计两个外键分别关联两张主表的主键,当然也可以设计一些其他的字段
(2)表结构上:只有两个一对多关系,数据上体现出两个一对多以及逻辑上的多对多关系

-- 学生表(主表)
drop table if exists student;
create table student(
    -- 学生表主键
    id int primary key auto_increment,
    name varchar(20) not null
);
-- 课程表(主表)
drop table if exists course;
create table course(
    -- 课程表主键
    id int primary key auto_increment,
    name varchar(20) not null
);
-- 中间表(从表):学生考试成绩表
drop table if exists exam_score;
create table exam_score(
    -- 学生考试成绩表主键
    id int primary key auto_increment,
    -- 学生表的主键作为中间表的外键
    student_id int,
    -- 课程表的主键作为中间表的外键
    course_id int,
    -- 建立主外键关系
    foreign key(student_id) references student(id),
    foreign key(course_id) references course(id)
);
-- 插入数据
insert into student values(1,'张三');
insert into student values(2,'李四');
insert into student values(3,'王五');
insert into course values(1,'语文');
insert into course values(2,'数学');
insert into exam_score(student_id,course_id) values(1,1);
insert into exam_score(student_id,course_id) values(1,2);
insert into exam_score(student_id,course_id) values(2,1);
insert into exam_score(student_id,course_id) values(2,2);
insert into exam_score(student_id,course_id) values(3,1);
insert into exam_score(student_id,course_id) values(3,2);

表的增删查改(进阶)—MySQL_第10张图片
表的增删查改(进阶)—MySQL_第11张图片

(3)关系
表的增删查改(进阶)—MySQL_第12张图片

3.插入数据

语法:insert into 表名(要插入的表名) select 要查询的字段 from 表名(要查询的表名) where …order by … limit;

3.1使用场景

(1)复制表
(2)提前准备一些统计的数据

-- 数据准备
-- 学生表
drop table if exists student;
create table student(
    id int primary key auto_increment,
    name varchar(20) not null
);
insert into student values(1,'张三');
insert into student values(2,'李四');
insert into student values(3,'王五');
-- 课程表
drop table if exists course;
create table course(
    id int primary key auto_increment,
    name varchar(20) not null
);
insert into course values(1,'语文');
insert into course values(2,'数学');
-- 学生考试成绩表
drop table if exists exam_score;
create table exam_score(
    id int primary key auto_increment,
    score decimal(4,1),
    student_id int,
    course_id int,
    foreign key(student_id) references student(id),
    foreign key(course_id) references course(id)
);
insert into exam_score(student_id,course_id,score) values(1,1,100);
insert into exam_score(student_id,course_id,score) values(1,2,110);
insert into exam_score(student_id,course_id,score) values(2,1,89);
insert into exam_score(student_id,course_id,score) values(2,2,99);
insert into exam_score(student_id,course_id,score) values(3,1,121);
insert into exam_score(student_id,course_id,score) values(3,2,111);
-- 学生成绩总表
drop table if exists score_total;
create table score_total(
    id int primary key auto_increment,
    score decimal(4,1),
    -- 学生信息
    student_id int,
    student_name varchar(20),
    -- 课程信息
    course_id int,
    course_name varchar(20)
);
-- 插入数据
insert into score_total(
    score,
    student_id,
    student_name,
    course_id,
    course_name
)select
    score,
    student_id,
    null,
    course_id,
    null
from exam_score where id between 2 and 5;

结果:
表的增删查改(进阶)—MySQL_第13张图片

4.查询数据

4.1聚合查询

查询返回结果集合,再进行聚合

4.1.1聚合函数

会将结果集所有数据进行聚合,合并为一行,使用分组操作也可以合并为多行
(1)sum(某个字段):求和
(2)avg(某个字段):求平均值
(3)max(某个字段):求最大值
(4)min(某个字段):求最小值
(5)count():获取整个结果集的行数(数据数量)

count(某个字段)=count(*)=count(常量值)
(常量值可以是0-n的任意数字)

-- 数据准备
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(math),avg(math),max(math),min(math) from exam_result;
select count(0) from exam_result;

表的增删查改(进阶)—MySQL_第14张图片
表的增删查改(进阶)—MySQL_第15张图片

4.1.2 group by(分组)

语法:select 查询字段 from 表名 where 条件 group by 分组字段1,分组字段2;

--  数据准备
-- 学生表
drop table if exists student;
create table student(
    id int primary key auto_increment,
    name varchar(20) not null
);
insert into student values(1,'张三');
insert into student values(2,'李四');
insert into student values(3,'王五');
-- 课程表
drop table if exists course;
create table course(
    id int primary key auto_increment,
    name varchar(20) not null
);
insert into course values(1,'语文');
insert into course values(2,'数学');
-- 学生考试成绩表
drop table if exists exam_score;
create table exam_score(
    id int primary key auto_increment,
    score decimal(4,1),
    student_id int,
    course_id int,
    foreign key(student_id) references student(id),
    foreign key(course_id) references course(id)
);
insert into exam_score(student_id,course_id,score) values(1,1,100);
insert into exam_score(student_id,course_id,score) values(1,2,110);
insert into exam_score(student_id,course_id,score) values(2,1,89);
insert into exam_score(student_id,course_id,score) values(2,2,99);
insert into exam_score(student_id,course_id,score) values(3,1,121);
insert into exam_score(student_id,course_id,score) values(3,2,111);
select student_id,sum(score),count(0) from exam_score group by student_id;

表的增删查改(进阶)—MySQL_第16张图片

select * from exam_score group by student_id;

表的增删查改(进阶)—MySQL_第17张图片

(1)执行过程:
①执行查询操作
②按分组字段进行分组
③把三个分组每个组里面的多条数据进行合并
(2)分组查询操作要求:
①查询字段必须是分组字段
②如果分组会造成聚合,非分组字段必须写在聚合函数中
③如果分组不会造成聚合,非分组字段可以直接写
(3)多个分组字段:常用于多表查询

select student_id,course_id,sum(score) from exam_score group by student_id,course_id;

表的增删查改(进阶)—MySQL_第18张图片

4.1.3having(分组后的过滤条件)

语法:select 查询字段 from 表名 where 条件 group by 分组字段 having 分组后条件;

(1)执行过程:
①执行查询操作
②分组
③分组条件过滤
(2)having是在分组后执行,having中的字段也需要满足分组查询操作的三个条件
(3)group by+having 经常用来查询重复数据

select student_id,course_id,sum(score) from exam_score group by student_id,course_id having count(0) > 1;

表的增删查改(进阶)—MySQL_第19张图片

4.2联合查询(多表查询,复合查询)

(1)多表联合查询操作使用字段的时候必须使用表名.字段名
(2)联合查询就是将单纯的笛卡尔积返回的结果进行过滤

-- 数据准备
drop database test;
create database test character set utf8mb4;
use test;
-- 学生表
drop table if exists student;
create table student(
    id int primary key auto_increment,
    name varchar(20) not null,
    classes_id int
);
insert into student(name,classes_id) values('张三',1);
insert into student(name,classes_id) values('李四',1);
insert into student(name,classes_id) values('王五',2);
-- 班级表
drop table if exists classes;
create table classes(
    id int primary key auto_increment,
    name varchar(20)
); 
insert into classes(name) values('数学系一班');
insert into classes(name) values('计算机系一班');
-- 课程表
drop table if exists course;
create table course(
    id int primary key auto_increment,
    name varchar(20) not null
);
insert into course values(1,'语文');
insert into course values(2,'数学');
-- 学生考试成绩表
drop table if exists exam_score;
create table exam_score(
    id int primary key auto_increment,
    score decimal(4,1),
    student_id int,
    course_id int,
    foreign key(student_id) references student(id),
    foreign key(course_id) references course(id)
);
insert into exam_score(student_id,course_id,score) values(1,1,100);
insert into exam_score(student_id,course_id,score) values(1,2,110);
insert into exam_score(student_id,course_id,score) values(2,1,89);
insert into exam_score(student_id,course_id,score) values(2,2,99);
insert into exam_score(student_id,course_id,score) values(1,1,77);
insert into exam_score(student_id,course_id,score) values(1,2,88);
insert into exam_score(student_id,course_id,score) values(2,1,133);
insert into exam_score(student_id,course_id,score) values(2,2,109);
insert into exam_score(student_id,course_id,score) values(3,1,121);
insert into exam_score(student_id,course_id,score) values(3,2,111);

表关系:
表的增删查改(进阶)—MySQL_第20张图片

4.2.1两个表的笛卡尔积

语法:select 表名.查询的字段 from 表1,表2;

(1)执行过程:(先遍历第一张表还是先遍历第二张表都可以)
①遍历第一张表的数据
②第一张表的每条数据和第二张表的每条数据相关联
③遍历第二张表的数据
(2)笛卡尔积的结果:两张表的每条数据相连接,产生一个结果集(虚拟表)
(3)结果集的行数=第一张表的行数*第二张表的行数
(4)单纯的笛卡尔积返回的数据没有什么意义

select * from student,classes;

表的增删查改(进阶)—MySQL_第21张图片

4.2.2内连接

语法:
select 查询字段 from 表1,表2 where 连接条件 and 其他条件
select 查询字段 from 表1 [inner] join 表2 on 连接条件 where 其他条件

(1)内连接中连接条件和其他条件没有什么区别
(2)执行过程
①使用联合查询:先用笛卡尔积,再进行where条件过滤

select * from student,classes 
    where student.classes_id = classes.id;

表的增删查改(进阶)—MySQL_第22张图片
②使用别名简化代码

select * from student as s,classes as c
    where s.classes_id = c.id;

③将 * 改为所有要查询的字段(建议的写法)

select 
    s.id s_id,
    s.name s_name,
    c.id c_id,
    c.name c_name 
from student s,classes c
    where s.classes_id = c.id;

表的增删查改(进阶)—MySQL_第23张图片
(3)内连接必须满足连接条件和其他条件才会返回
(4)关联两张以上的表

select 
    s.id s_id,
    s.name s_name,
    c.id c_id,
    c.name c_name,
    e.score,
    e.course_id
from student s,classes c,exam_score e
    where s.classes_id = c.id
    and s.id = e.student_id;

(5)查询课程id=1的所有班级的平均分

select
    c.id c_id,
    c.name c_name,
    avg(e.score)
from student s, classes c,exam_score e
    where s.classes_id = c.id
    and s.id = e.student_id
    and e.course_id = 1
group by c.id;

表的增删查改(进阶)—MySQL_第24张图片
(6)查询“语文”课程的所有班级的平均分

select
    c.id c_id,
    c.name c_name,
    cou.name cou_name,
    avg(e.score)
from student s,classes c,exam_score e,course cou
    where s.classes_id = c.id
    and s.id = e.student_id
    and e.course_id = cou.id
    and cou.name = '语文'
group by c.id;

表的增删查改(进阶)—MySQL_第25张图片
(7)查询所有课程的所有班级的平均分

select
    c.id c_id,
    c.name c_name,
    cou.name cou_name,
    avg(e.score)
from student s,classes c,exam_score e,course cou
    where s.classes_id = c.id
    and s.id = e.student_id
    and e.course_id = cou.id
group by c.id,cou.id;
-- join on 写法
select
    c.id c_id,
    c.name c_name,
    cou.name cou_name,
    avg(e.score)
from student s
    join classes c on s.classes_id = c.id
    join exam_score e on s.id = e.student_id
    join course cou on e.course_id = cou.id
group by c.id,cou.id;

表的增删查改(进阶)—MySQL_第26张图片

4.2.3外连接

语法:
左外连接:select 查询字段 from 左表 left join 右表 on 连接条件 where 其他条件
右外连接:select 查询字段 from 左表 right join 右表 on 连接条件 where 其他条件

(1)左外连接的左表和右外连接的右表是外表

-- 班级表作为外表,即使班级中没有数据,也可以显示,但是内连接就不可以显示
-- 插入数据
insert into classes(name) values('会计系一班');
select 
    s.id s_id,
    s.name s_name,
    c.id c_id,
    c.name c_name,
    s.classes_id
from student s
    right join classes c 
    on s.classes_id = c.id;

表的增删查改(进阶)—MySQL_第27张图片
(2)外连接满足连接条件和其他条件或者满足其他条件但是外表存在,即使不满足连接条件也可以返回

4.2.4内连接和外连接的区别

(1)内连接必须满足连接条件和其他条件才会返回
(2)外连接满足连接条件和其他条件或者满足其他条件但是外表存在,即使不满足连接条件也可以返回

4.2.5自连接

(1)表自己连接自己
(2)常用于自身多行数据,同一个字段进行比较操作

-- 查询课程id = 1成绩大于课程id = 2
select
    *
from exam_score e1,exam_score e2
    where e1.student_id = e2.student_id
    and e1.course_id = 1
    and e2.course_id = 2
    and e1.score > e2. score;
-- 查询语文成绩大于数学成绩
select
    e1.student_id,
    e1.score '语文成绩',
    e2.score '数学成绩'
from exam_score e1,exam_score e2,course c1,course c2
    where e1.student_id = e2.student_id
    and c1.name = '语文'
    and c2.name = '数学'
    and e1.score > e2. score;

4.2.6子查询

(1)子查询返回一行数据,可以当做常量

语法:
– 单行子查询
select … from 表1 where 字段1 = (select … from …);

-- 查询张三同学的同班同学
select
    *
from student
where classes_id = (
    select classes_id from student where name = '张三'
);

表的增删查改(进阶)—MySQL_第28张图片

(2)[not] in

语法:
select … from 表1 where 字段1 in (select … from …);

-- 查询张三和李四的成绩
select
    *
from exam_score
where student_id in(
    select id from student where name = '张三' or name = '李四'
);
-- 插入数据
insert into exam_score(score,student_id,course_id)
    values (110,1,2),(89,2,1);
-- 查询重复的分数
select
    *
from exam_score
where (score,student_id,course_id)
in(select 
    score,student_id,course_id
from exam_score
group by score,student_id,course_id
having count(0) > 1
);

表的增删查改(进阶)—MySQL_第29张图片
表的增删查改(进阶)—MySQL_第30张图片

(3)[not] exists

语法:select … from 表1 where exists (select … from … where 条件);

-- 查询张三和李四的成绩
select
    *
from exam_score e
where exists(
    select 1 from student s 
    where e.student_id = s.id
    and (s.name = '张三' or s.name = '李四')
);

(4) 临时表:from子句中的子查询

语法:select … from 表1, (select … from …) as tmp where 条件;

-- 查询平均分数比“数学系一班”高的班级
-- 查平均分
select 
    avg(e.score)
from exam_score e,student s,classes c
    where e.student_id = s.id
    and s.classes_id = c.id
    and c.name = '数学系一班';
select 
    es.*
from exam_score es,
    (select 
    avg(e.score) avg_score
    from exam_score e,student s,classes c
    where e.student_id = s.id
    and s.classes_id = c.id
    and c.name = '数学系一班')tmp
where es.score > tmp.avg_score;

表的增删查改(进阶)—MySQL_第31张图片

4.2.7合并查询

(1)union all:取两个结果集的并集

select
    *
    from course 
    where id <= 2
    union 
    select * from course where name = '语文';

表的增删查改(进阶)—MySQL_第32张图片

(2)union:取两个结果集的并集,并去重(按照结果集所有查询字段去重)

select
    *
    from course 
    where id <= 2
    union all
    select * from course where name = '语文';

表的增删查改(进阶)—MySQL_第33张图片
(3)单表的结果集取并集其实是可以使用or实现的,但是union是使用两个结果集
(4)两个结果集的查询字段,顺序,数量要一致

你可能感兴趣的:(MySQL,mysql,数据库,sql)