约束:按照一定的条件进行规范的做事,表定义的时候,某些字段保存的数据,需要按照一定的约束条件
(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 ('张三');
表示某个字段,不能重复,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,'张三');
(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);
(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 ('李四');
(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 ('王五');
(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),
);
drop table if exists student;
create table student (
id int,
name varchar(20),
sex varchar(1),
-- sex只能是男和女,插入其他的就会报错
check (sex ='男' or sex='女')
);
数据库的表设计就是建立一种对象模型
(1)语法上只有一中写法
主表的主键关联从表的外键(实际上建立外键,不一定要使用主键来关联)
(2)写法
(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 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);
语法:insert into 表名(要插入的表名) select 要查询的字段 from 表名(要查询的表名) where …order by … limit;
(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;
查询返回结果集合,再进行聚合
会将结果集所有数据进行聚合,合并为一行,使用分组操作也可以合并为多行
(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;
语法: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;
select * from exam_score group by student_id;
(1)执行过程:
①执行查询操作
②按分组字段进行分组
③把三个分组每个组里面的多条数据进行合并
(2)分组查询操作要求:
①查询字段必须是分组字段
②如果分组会造成聚合,非分组字段必须写在聚合函数中
③如果分组不会造成聚合,非分组字段可以直接写
(3)多个分组字段:常用于多表查询
select student_id,course_id,sum(score) from exam_score group by student_id,course_id;
语法: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;
(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);
语法:select 表名.查询的字段 from 表1,表2;
(1)执行过程:(先遍历第一张表还是先遍历第二张表都可以)
①遍历第一张表的数据
②第一张表的每条数据和第二张表的每条数据相关联
③遍历第二张表的数据
(2)笛卡尔积的结果:两张表的每条数据相连接,产生一个结果集(虚拟表)
(3)结果集的行数=第一张表的行数*第二张表的行数
(4)单纯的笛卡尔积返回的数据没有什么意义
select * from student,classes;
语法:
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;
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;
(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;
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;
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;
语法:
左外连接: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;
(2)外连接满足连接条件和其他条件或者满足其他条件但是外表存在,即使不满足连接条件也可以返回
(1)内连接必须满足连接条件和其他条件才会返回
(2)外连接满足连接条件和其他条件或者满足其他条件但是外表存在,即使不满足连接条件也可以返回
(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;
(1)子查询返回一行数据,可以当做常量
语法:
– 单行子查询
select … from 表1 where 字段1 = (select … from …);
-- 查询张三同学的同班同学
select
*
from student
where classes_id = (
select classes_id from student where name = '张三'
);
(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
);
(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;
(1)union all:取两个结果集的并集
select
*
from course
where id <= 2
union
select * from course where name = '语文';
(2)union:取两个结果集的并集,并去重(按照结果集所有查询字段去重)
select
*
from course
where id <= 2
union all
select * from course where name = '语文';
(3)单表的结果集取并集其实是可以使用or实现的,但是union是使用两个结果集
(4)两个结果集的查询字段,顺序,数量要一致