创建表时可以指定某列不能为空
只需在对应列的后面加上 not null
例:创建一个学生表,指定 id 不能为空
create table student (id int not null, name varchar(10));
创建成功后我们可以查看表结构
desc student;
我们可以看见 id 对应的 null 列显示的 NO 表明插入数据时id不能为null
当我们尝试给id插入null值会提示报错信息
创建表时,在某列的后面加上unique 可以指定该列的值不能重复
例:创建一个学生表,要求id的值不能重复
create table student(id int unique, name varchar(10));
我们查看表的结构,可以发现Key 下面对应id的行多了UNI
当我们向表中插入数据时,如果该数据的id在表中已有了则会插入失败
注意:如果是修改表中原有的数据也要注意,修改id时不能与其他行重复
在创建表时可以在某列的后面加上 (default 默认值)
在插入数据时如果,没有给出该列的值,则会把这个默认值当作该列的值
例:创建一个学生表,指定 name 默认值为 " 佚名"
create table student (id int, name varchar(10) default "佚名");
查看表可以发现,name 对应的default 变为了佚名
当我们插入数据时,没有给出name的值时则会自动给出 佚名,不过要注意如果给出null值的话,name则就为null不会被默认值替换
被primary key 约束的列,值不能为null且不能重复
例:
以id为主键创建学生表
create table student (id int primary key, name varchar(10));
查看表可以看到id对应的key列下多了PRI
对于整数类型的主键,常配搭自增长auto_increment来使用。插入数据对应字段不给值或给null值时,使之为该列最大值+1(第一个数据时默认为1)
create table student (id int primary key auto_increment, name varchar(10));
注意:如果我们删除第二条数据再插入id默认值将不会从2开始而是从3开始,如果要插入id为3的数据只能手动插入
作用:
加速数据检索:定义主键后,MySQL 会自动为主键列创建索引(下期会讲),这将大大加快基于主键列的数据检索速度。当使用主键进行查询时,数据库引擎会直接定位到相应的行,而不需要全表扫描。
用于建立关系:在关系型数据库中,主键通常用于建立不同表之间的关系。通过在其他表中引用包含主键的表,可以建立表与表之间的关联,实现数据的关联性查询和完整性约束。
primary key 和 not null unique 的区别:
以定义 列 id为例:
id int PRIMARY KEY:
id int NOT NULL UNIQUE:
因此,在功能上,这两种定义方式都会实现 id 列的唯一性并禁止空值,但使用 PRIMARY KEY 会将 id 列明确地指定为表的主键,而使用 UNIQUE 索引则没有将 id 列明确指定为主键,也允许 NULL 值的存在。通常情况下,如果 id 列是表中的唯一标识符,更推荐使用 id int PRIMARY KEY 这种方式,因为它能够清晰地表明 id 列是主键。
外键用于关联其他表的主键或唯一键
语法:
foreign key (列名) references 主表名(主键列名)
作用:
确保引用完整性: 外键约束可以确保引用完整性,即确保在一个表中引用另一个表中已经存在的数据。这意味着,如果在一个表中定义了外键约束,那么在插入或更新数据时,要求引用的数据必须存在于被引用的表中。
维护表之间的关联: 外键约束能够维护表与表之间的关联关系,确保相关表中的数据保持一致性。通过外键约束,一个表中的数据与另一个表中的数据进行关联,从而帮助数据库系统对数据之间的关系进行管理和维护。
防止孤儿记录: 外键约束可以防止产生孤儿记录,即一个表中引用另一个表中不存在的数据。这样可以确保数据的完整性,避免因为引用了不存在的数据而导致数据不一致的情况发生。
维护数据一致性: 通过外键约束,可以确保在相关表中的数据一致性,当父表中的数据发生变化时,可以通过外键约束来对子表中的数据进行级联操作,从而维护数据的一致性。
例:
创建一个班级表 令id为主键
create table class_java (id int primary key auto_increment, name varchar(20));
创建一个学生表以班级id class_id 为外键 关联班级表id
create table student (
id int primary key auto_increment,
name varchar(20),
class_id int,
foreign key (class_id) references class_java(id)
);
在班级表中插入数据
在学生表中插入数据(class_id 只能是 class表中有的值,否则会报错)
注意如果要删除数据,只能先删除子表的数据当父表中的某个引用值在子表中不存在时才能修改或删除该值,例如要把3该为4 只能先删除学生表中class_id 为3 的所有学生才能修改
可以把一张表的查寻结果插入另一张表中,列的数据类型必须对应
例: 把上面学生表的id和姓名插入用户表 user中
创建用户表user
create table user(id int, name varchar(20));
插入:
insert into user select id, name from student;
普通的查询方式不能进行行与行之间的运算,这时候就需要聚合查询
函数 | 说明 |
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的 总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
例:
统计学生表学生的数量:
select count(*) from student;
统计学生表学生id的总和:
select sum(id) from student;
select 中使用group by 可以对指定列进行分组查询
使用 GROUP BY 进行分组查询时,SELECT 指定的字段必须是“分组依据字段”,其他字段若想出现在SELECT 中则必须包含在聚合函数中,否则将只输出每组的第一个数据
例:创建职员表,有id(主键)、name(姓名)、role(角色)、salary(薪水)
create table emp(
id int primary key auto_increment,
name varchar(20) not null,
role varchar(20) not null,
salary numeric(11,2)
);
插入数据
查询每个职位的最高工资、最低工资和平均工资
select role, max(salary), min(salary), avg(salary) from emp group by role;
where 只能对分组前的数据进行筛选,要对分组后的结果进行筛选时要用having
例:
显示平均工资低于25000的职位和它的平均工资
select role, avg(salary) from emp group by role having avg(salary) > 25000;
实际开发中往往数据来自不同的表,所以需要多表联合查询。多表查询是对多张表的数据取笛卡尔积
初始化测试数据:
上面我们有了学生表和班级表,我们再创建一个课程表与分数表:
创建课程表:
create table course(id int primary key auto_increment, name varchar(20));
创建分数表:
create table score(
id int primary key auto_increment,
score int,
student_id int,
course_id int,
foreign key (student_id) references student(id),
foreign key (course_id) references course(id)
);
插入一些数据:
insert into course(name) values
-> ("JavaSE语法"),
-> ("数据结构"),
-> ("MySQL"),
-> ("JavaEE");
insert into score(score, student_id, course_id) values
-- 小明
(70, 2001, 1), (98, 2001, 3), (33, 2001, 4),
-- 小芳
(60, 2002, 1), (59, 2002, 2),
-- 小李
(33, 2003, 1),(68, 2003, 3),(99, 2003, 4),
-- 小芬
(67, 2004, 1),(23, 2004, 2),(56, 2004, 3),
-- 小刚
(81, 2005, 1),(37, 2005, 4),
-- 小华
(56, 2006, 2),(43, 2006, 3),(79, 2006, 4);
语法:
select 字段 from 表1 别名1 [inner] join 表2 别名2 on 连接条件 and 其他条件;
select 字段 from 表1 别名1,表2 别名2 where 连接条件 and 其他条件;
例:
查询小芬同学的课程id 和 对应成绩
select score.course_id, score.score from student join score on student.name = "小芬" and score.student_id = student.id;
查询每个同学的 姓名 和每个课程的 名称 以及对应的 得分
select student.name, course.name, score.score from
student, course, score where
score.student_id = student.id and
score.course_id = course.id;
内连接只能显示对应行中有数据的行
外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就说是右外连接。
语法:
-- 左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;
例:查询所有同学的成绩,及同学的个人信息,如果该同学没有成绩,也需要显示
我们再插入一个同学:
按要求查询成绩:
select student.id, student.name, course.name, score.score
from student
left join score on
student.id = score.student_id
left join course on
course.id = score.course_id;
自连接是指在同一张表连接自身进行查询
查询 avaSE语法 成绩大于 JavaEE 成绩的同学信息以及这两科的成绩
select student.id, student.name, c1.name, s1.score, c2.name, s2.score
from student
join score as s1 on student.id = s1.student_id
join course as c1 on c1.id = s1.course_id and c1.name = "JavaEE"
join score as s2 on student.id = s2.student_id and s1.score < s2.score
join course as c2 on c2.id = s2.course_id and c2.name = "JavaSE语法";
注意:自连接时要给列取别名 来区分两列
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询
单子查询:
例:查询与小明同班的同学
select * from student where class_id = (
select class_id from student where name = "小明");
多子查询:
1. (not) in
查询JavaEE或MySQL的成绩
select * from score where course_id in (
select id from course where name = "JavaEE" or name = "MySQL");
加上not则是查 avaEE,MySQL以外的成绩
2. (not) exists
select * from score where exists (
select id from course where (name = "JavaEE" or name = "MySQL")
and score.course_id = course.id);