【MySQL】数据库约束和多表查询

目录

1.前言

2.数据库约束

2.1约束类型

[2.2 NULL约束](#2.2 NULL约束)

[2.3 NUIQUE:唯一约束](#2.3 NUIQUE:唯一约束)

[2.4 DEFAULT:默认值约束](#2.4 DEFAULT:默认值约束)

[2.5 PRIMARY KEY:主键约束](#2.5 PRIMARY KEY:主键约束)

[2.6 FOREIGN KEY:外键约束](#2.6 FOREIGN KEY:外键约束)

[1.7 CHECK约束](#1.7 CHECK约束)

3.表的设计

3.1一对一

3.2一对多

3.3多对多

4.新增

5.查询

5.1聚合查询

5.1.1聚合函数

[5.1.2 GROUP BY子句](#5.1.2 GROUP BY子句)

[5.1.3 HAVING](#5.1.3 HAVING)

5.2联合查询

5.2.1内连接

5.2.2外连接

5.2.3自连接

5.2.4子查询

5.2.5合并查询

6.总结


1.前言

我们上一次介绍了MySQL数据库关于表的增删改查,在平时是用的过程还需要对数据库进行约束以及多表查询,因此今天跟大家分享并介绍数据库约束和多表查询的内容。

2.数据库约束

2.1约束类型

NOT NULL: 指示某列不能存储NULL值。

UNIQUE:保证某列的每行必须有唯一的值。

DEFAULT:规定没有给列赋值时的默认值。

PRIMARY KEY:确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。

FOREIGN KEY:保证一个表中的数据匹配另一个表中的值的参照完整性。

CHECK :保证列中的值符合指定的条件。对于MySQL数据库,对CHECK子句进行分析,但是忽略CHECK子句。

2.2 NULL****约束

我们在数据库创建表时,可以指定某列不为空,比如我们在创建一个学生表时,可以对表的结构进行设置。

sql 复制代码
-- 创建学生表并设置学生表结构
create table student (
id int not null,
sn int,
name varchar(20),
qq_mail varchar(20)
);

2.3 NUIQUE:唯一约束

指定sn列中的值唯一且不重复的,比如我们重新设置学生表的结构:

sql 复制代码
-- 重新设置学生表结构
drop table if exists student;
create table student (
id int not null,
sn int unique,
name varchar(20),
qq_mail varchar(20)
);

2.4 DEFAULT**:默认值约束**

指定插入数据时, name 列为空,默认值 unkown :

sql 复制代码
-- 重新设置学生表结构
drop table if exists student;
create table student (
id int not null,
sn int unique,
name varchar(20)  default 'unkown',
qq_mail varchar(20)
);

2.5 PRIMARY KEY**:主键约束**

指定 id 列为主键:

sql 复制代码
-- 重新设置学生表结构
drop table if exists student;
create table student (
id int not null primary key,
sn int unique,
name varchar(20)  default 'unkown',
qq_mail varchar(20)
);


对于整数类型的主键,常配搭自增长 auto_increment 来使用。插入数据对应字段不给值时,使用最大值+1 。

sql 复制代码
-- 主键是 NOT NULL 和 UNIQUE 的结合,可以不用 NOT NULL
id INT PRIMARY KEY auto_increment

2.6 FOREIGN KEY:外键约束

外键用于关联其他表的主键唯一键。

sql 复制代码
foreign key (字段名) references 主表(列)

下面以创建一个班级表和学生表为例:

  • 创建班级表classes,id为主键
sql 复制代码
-- 创建班级表,有使用MySQL关键字作为字段时,需要使用``来标识
create table classes (
id INT PRIMARY KEY auto_increment,
name VARCHAR(20),
`desc` VARCHAR(100)
);
  • 创建学生表student,一个学生对于一个班级,一个班级对应多个学生。使用id为主键,class_id为外键,关联班级表id。
sql 复制代码
-- 创建学生表
drop table if exists student;
create table student (
id int not null primary key,
sn int unique,
name varchar(20)  default 'unkown',
qq_mail varchar(20),
classes_id int,
foreign key (classes_id) references classes(id)
);

1.7 CHECK****约束

MySQL使用时不报错,但忽略该约束。

sql 复制代码
create table test_user (
id int,
name varchar(20),
sex varchar(1),
check (sex = '男' or sex = '女')
);

3.表的设计

3.1一对一

比如:一个学生只能对应一个身份证,一个身份证也只能对应一个学生。

3.2一对多

一个班级有多个学生,但一个学生只能对应一个班级。

3.3多对多

一个学生能够选择多门课程,一个课程可以被多个学生选择。

4.新增

语法:

sql 复制代码
INSERT INTO table_name [(column [, column ...])] SELECT ...

给大家举个例子:创建一张用户表,设计有 name 姓名、 email 邮箱、 sex 性别、 mobile 手机号字段。需要把已有的学生数据复制进来,可以复制的字段为name,qq_ mail。

sql 复制代码
-- 创建用户表
DROP TABLE IF EXISTS test_user;
CREATE TABLE test_user (
id INT primary key auto_increment,
name VARCHAR(20) comment '姓名',
age INT comment '年龄',
email VARCHAR(20) comment '邮箱',
sex varchar(1) comment '性别',
mobile varchar(20) comment '手机号'
);

-- 新增班级数据
insert into classes values(601,"六年级一班","1班");

-- 新增学生数据
insert into student values(1,100,"张三","123@qq.com",601);
insert into student values(2,101,"李四","456@qq.com",601);

-- 将学生表中的所有数据复制到用户表
insert into test_user(name, email) select name, qq_mail from student;

-- 查询用户表
select * from test_user;

5.查询

5.1聚合查询

5.1.1聚合函数

常见的统计总数、计算平局值等操作,可以使用 聚合函数 来实现,常见的聚合函数有:

|--------------------------|-----------------------|
| 函数 | 说明 |
| COUNT([DISTINCT] expr) | 返回查询到的数据的数量 |
| SUM([DISTINCT] expr) | 返回查询到的数据的总和,不是数字没有意义 |
| AVG([DISTINCT] expr) | 返回查询到的数据的平均值,不是数字没有意义 |
| MAX([DISTINCT] expr) | 返回查询到的数据的最大值,不是数字没有意义 |
| MIN([DISTINCT] expr) | 返回查询到的数据的最小值,不是数字没有意义 |

  • COUNT
sql 复制代码
-- 统计班级共有多少同学
SELECT COUNT(*) FROM student;

-- 统计班级收集的qq_mail 有多少个,qq_mail 为 NULL 的数据不会计入结果
SELECT COUNT(qq_mail) FROM student;
  • SUM
sql 复制代码
-- 统计数学成绩总分
select sum(math) from exam;

-- 统计所有数学成绩不及格(<60)人的数学总分,没有则返回NULL
select sum(math) from exam where math < 60;
  • AVG
sql 复制代码
-- 统计平均总分
select avg(Chinese + math + English) from exam;
  • MAX
sql 复制代码
-- 返回数学最高分
select max(math) from exam;
  • MIN
sql 复制代码
-- 返回 > 70 分以上的数学最低分
select min(math) from exam where math > 70;

5.1.2 GROUP BY****子句

SELECT 中使用 GROUP BY 子句可以对指定列进行分组查询。需要满足: 使用 GROUP BY 进行分组查询时,SELECT 指定的字段必须是"分组依据字段",其他字段若想出现在SELECT 中则必须包含在聚合函数中。
语法:

sql 复制代码
select column1, sum(column2), .. fromtablegroupby column1,column3;

举个例子:

  • 准备测试表及数据:员工表,有id(主键)、name(姓名)、role(角色)、salary(薪水)
sql 复制代码
-- 创建员工表
create table emp (
id int primary key auto_increment,
name varchar(20) not null,
role varchar(20) not null,
salary numeric(11,2)
);

-- 添加员工数据
insert into emp(name, role, salary) values
('张三','服务员', 1000.20),
('李四','游戏陪玩', 2000.99),
('孙悟空','游戏角色', 999.11),
('猪无能','游戏角色', 333.5),
('沙和尚','游戏角色', 700.33),
('王五','董事长', 12000.66);
  • 查询每个角色的最高工资、最低工资和平均工资。
sql 复制代码
select role, max(salary), min(salary), avg(salary) from emp group by role;

5.1.3 HAVING

GROUP BY 子句进行分组以后 ,需要对分组结果再 进行条件过滤 时, 不能使用 WHERE 语句 ,而 需要用HAVING。

  • 显示平均工资低于1500的角色和它的平均工资
sql 复制代码
select role, avg(salary) from emp group by role having avg(salary) < 1500;

5.2联合查询

实际开发中数据往往来自不同的表,所以需要多表联合查询。多表查询是对多张表的数据取笛卡尔积:

注意:关联查询可以对关联表使用别名。、

下面展示初始化测试数据:

sql 复制代码
-- 在班级表中新增数据
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);

-- 创建课程表
create table course(id int primary key auto_increment, name varchar(20));

-- 在课程表中新增数据
insert into course(name) values
('Java'),
('中国传统文化'),
('计算机原理'),
('语文'),
('高阶数学'),
('英文');

-- 创建成绩表
create table score(score decimal(3, 1), student_id int, course_id int);

--在成绩表中新增数据
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);

5.2.1内连接

语法:

sql 复制代码
select 字段 from表1 别名1 [inner] join表2 别名2 on 连接条件 and 其他条件;
select 字段 from表1 别名1,表2 别名2 where 连接条件 and 其他条件;

例如:(1)查询"许仙"同学的成绩

sql 复制代码
select stu.name, sco.score from student as stu join score as sco on stu.id = sco.student_id and stu.name = '许仙';

-- 也可以采用下面这种方法
select stu.name, sco.score from student as stu, score as sco where stu.id = sco.student_id and stu.name = '许仙';

(2)查询所有同学的总成绩,及同学的个人信息:

sql 复制代码
-- 成绩表对学生表是多对一关系,查询总成绩是根据成绩表的同学id来进行分组的
select stu.sn, stu.name, stu.qq_mail, sum(sco.score) 
from 
student as stu join score as sco 
on stu.id = sco.student_id 
group by sco.student_id;

(3)查询所有同学的成绩,及同学的个人信息:

sql 复制代码
-- 查询出来的都是有成绩的同学,"老外学中文"同学没有显示
select * from student stu join score sco on stu.id=sco.student_id;
sql 复制代码
-- 学生表、成绩表、课程表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;

5.2.2外连接

外连接分为左外连接和右外连接。如果联合查询,左侧的表完全显示我们就说是左外连接;右侧的表完全显示我们就是是右外连接。

语法:

sql 复制代码
-- 左外连接,表1完全显示
select 字段名 from 表名1 left join表名2 on 连接条件;

- 右外连接,表2完全显示
select 字段名 from 表名1 right join表名2 on 连接条件;

例如查询所有同学的成绩,及同学的个人信息,如果该同学没有成绩,也需要显示出来。

sql 复制代码
-- "老外学中文"同学没有考试成绩,也显示出来了
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;

sql 复制代码
-- 学生表、成绩表、课程表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;

5.2.3自连接

自连接是指在同一张表连接自身进行查询。
例如:显示所有"计算机原理"成绩比"Java"成绩高的成绩信息。

sql 复制代码
-- 先查询"计算机原理"和"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;

5.2.4子查询

子查询是指嵌入在其他 sql 语句中的 select 语句,也叫嵌套查询。
注意:编程中的基本思想原则化繁为简,但子查询是化简为繁,我们要慎重使用,避免出错。

  • 单行子查询:返回一行记录的子查询

比如:查询与 " 不想毕业 " 同学的同班同学:

sql 复制代码
select * from student where classes_id=(select classes_id from student where name='不想毕业');
  • 多行子查询:返回多行记录的子查询

例如:查询 " 语文 " 或 " 英文 " 课程的成绩信息。
1. [NOT] IN关键字:

sql 复制代码
-- 使用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!='英文');

注意:

在 from 子句中使用子查询:子查询语句出现在 from 子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。

5.2.5合并查询

在实际应用中,为了合并多个 select 的执行结果,可以使用集合操作符 union,union all 。使用 UNION和UNION ALL 时,前后查询的结果集中,字段需要一致。

  • union

该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。

例如:查询id小于3,或者名字为"英文"的课程:

sql 复制代码
select * from course where id<3
union
select * from course where name='英文';

-- 或者使用or来实现
select * from course where id<3 or name='英文';
  • union all

该操作符用于取得两个结果集的并集。 当使用该操作符时,不会去掉结果集中的重复行。
举个例子:查询 id 小于 3 ,或者名字为 "Java" 的课程

sql 复制代码
-- 可以看到结果集中出现重复数据Java
select * from course where id<3
union all
select * from course where name='Java';

6.总结

SQL 查询中各个关键字的执行先后顺序: from > on> join > where > group by > with > having > select > distinct > order by > limit, 我们在编写SQL语句时要按照上面的执行顺序去编写,才能成功运行获取到想要查询的数据,以上就是本次所介绍的内容,我们下次再跟继续大家分享MySQL数据库中的索引与事务!

相关推荐
Elastic 中国社区官方博客3 小时前
在 Elasticsearch 中使用 Mistral Chat completions 进行上下文工程
大数据·数据库·人工智能·elasticsearch·搜索引擎·ai·全文检索
编程爱好者熊浪4 小时前
两次连接池泄露的BUG
java·数据库
南宫乘风5 小时前
基于 Flask + APScheduler + MySQL 的自动报表系统设计
python·mysql·flask
TDengine (老段)6 小时前
TDengine 字符串函数 CHAR 用户手册
java·大数据·数据库·物联网·时序数据库·tdengine·涛思数据
qq7422349846 小时前
Python操作数据库之pyodbc
开发语言·数据库·python
姚远Oracle ACE6 小时前
Oracle 如何计算 AWR 报告中的 Sessions 数量
数据库·oracle
Dxy12393102167 小时前
MySQL的SUBSTRING函数详解与应用
数据库·mysql
码力引擎7 小时前
【零基础学MySQL】第十二章:DCL详解
数据库·mysql·1024程序员节
杨云龙UP7 小时前
【MySQL迁移】MySQL数据库迁移实战(利用mysqldump从Windows 5.7迁至Linux 8.0)
linux·运维·数据库·mysql·mssql
l1t7 小时前
利用DeepSeek辅助修改luadbi-duckdb读取DuckDB decimal数据类型
c语言·数据库·单元测试·lua·duckdb