MySQL之外键、表关系及SQL查询关键字

一、外键

假设我们现在有一个员工信息表,其中包含以下字段:

[En]

Suppose we now have an employee information table with the following fields:

id  # 主键
name  # 姓名
age  # 年龄
dep_name  # 部门名称
dep_desc  # 部门描述

仅就数据存储而言,这个表是可以的,但从程序开发的角度来看,这个表目前存在以下三个缺陷:

[En]

In terms of data storage alone, this table is fine, but from a program development point of view, this table currently has the following three defects:

  1. 表的重点不清晰:到底是员工表还是部门表(其实可以忽略)
  2. 表中字段会出现重复存储,如数据量较大,那么会存储多个相同部门的名称和描述(其实也可以忽略)
  3. 表的扩展性极差,如要修改某个部门名称信息,就会导致牵一发而动全身 (这一点不能忽略)

如何解决上述三个缺陷?

[En]

How to solve the above three defects?

其实我们可以将上述表拆分成两张表,一张员工表(emp),一张部门表(dep):

emp表:
id  name  age

dep表:
id dep_name dep_desc

如此一来,上述三个缺陷都得到了解决,但也要发现一个小问题,那就是两个表之间的数据没有关系,那么如何解决表之间的关系呢?

[En]

In this way, all the above three defects have been solved, but you should also find a small problem, that is, there is no relationship between the data between the two tables, so how to solve the relationship between tables?

于是,MySQL给我们提供了 外键:foreign key这种约束方式来帮我们解决上述问题,

通过建立外键字段来标识表和表之间的数据关系,还可以简单地理解为该字段允许您在其他表中查找数据。

[En]

By establishing a foreign key field to identify the data relationship between the table and the table, it can also be simply understood that the field allows you to look for data in other tables.

让我们来看看如何以这种方式添加表之间的关系。

[En]

Let’s take a look at how to add relationships between tables in this way.

二、表与表之间建立关系

表之间有三种关系,如下所示:

[En]

There are three relationships between tables, as follows:

  • 一对多
  • 多对多
  • *一对一

其实我们日常所能接触到的最常见的关系反而不是这三种,而是 没有关系

当然, 没有关系 我们是比较容易判断的,那么对于上面三种关系,我们又该如何判断呢,这里我推荐一种判断表的方式,那就是 换位思考,接下来就来看看这种方式在三种关系判断中是如何体现的。

2.1 一对多

以员工和部门表为例:

  • 以工作人员表为基础:
    [En]

    stand on the basis of the staff table:*

  • 问:一个员工信息能否对应多个部门信息
  • 答:不可以
  • 站在部门表的基础上:
    [En]

    stand on the basis of the department table:*

  • 问:一个部门信息能否对应多个员工信息
  • 答:可以

结论:

一个可以,一个不可以,那么表关系就是 一对多
针对 一对多 的表关系,外键字段建在多的一方;
表关系没有 多对一 一说,都是 一对多

在上面的示例中,Employee表是多个,而Department表是一个。

[En]

In the above example, the employee table is many and the department table is one.

SQL语句实现如下:

"""先创建不含外键字段的基本表,之后再添加外键字段"""
"""部门表"""
create table dep(
    id int primary key auto_increment,
    dep_name varchar(32),
    dep_desc varchar(254)
);

"""员工表"""
create table emp(
    id int primary key auto_increment,
    name varchar(32),
    age int,
    dep_id int,
    foreign key(dep_id) references dep(id)
)

2.2 多对多

以书籍表和作者表为例:

  • 以书单为依据:
    [En]

    stand on the basis of the list of books:*

  • 问:一个书籍信息能否对应多个作者信息
  • 答:可以
  • 站在作者表的基础上:
    [En]

    stand on the basis of the author’s table:*

  • 问:一个作者信息能否对应多个书籍信息
  • 答:可以

结论:

两个都可以,那么表关系就是 多对多
针对 多对多表关系,需要单独开设第三张表存储两张表的关联数据(第三张表也可以不绑定关系)

SQL语句实现如下:

"""书籍表"""
create table book(
    id int primary key auto_increment,
    title varchar(32),
    price float(6,2)
);

"""作者表"""
create table author(
    id int primary key auto_increment,
    name varchar(32),
    age int
);

"""第三张关系表"""
create table book2author(
    id int primary key auto_increment,
    book_id int,
    author_id int,
    foreign key(book_id) references book(id)
    on update cascade   # 级联更新
    on delete cascade,  # 级联删除
    foreign key(author_id) references author(id)
    on update cascade   # 级联更新
    on delete cascade  # 级联删除
);

2.3 一对一

以作者表和作者明细表为例:

[En]

Take the author table and the author details table as an example:

  • 站在作者表的基础上:
    [En]

    stand on the basis of the author’s table:*

  • 问:一个作者信息能否对应多个作者详情信息
  • 答:不可以
  • 以作者明细表为依据:
    [En]

    stand on the basis of the author’s details table:*

  • 问:一个作者详情信息能否对应多个作者信息
  • 答:不可以

结论:

两个都不可以,那么表关系可能是 一对一或者 没有关系,这个视具体情况应该就能判断出来;
针对 一对一表关系,外键字段建在任何一方都可以,但是推荐建在查询频率较高的表中;

SQL语句实现如下:

"""作者详情表"""
create table author_detail(
    id int primary key auto_increment,
    phone bigint,
    address varchar(32)
);

"""作者表"""
create table author(
    id int primary key auto_increment,
    name varchar(32),
    age int,
    author_id int unique,    # 要加上唯一约束条件,这是与一对多表关系唯一不同的地方
    foreign key(author_id) references author_detail(id)
    on update cascade   # 级联更新
    on delete cascade   # 级联删除
);

2.4 外键约束

  • 创建表时,需要创建关联表(不带外键字段的表)
    [En]

    when creating a table, you need to create an associated table (a table without foreign key fields)*

  • 插入新数据时,应首先确保关联表中有数据
    [En]

    when inserting new data, you should first ensure that there is data in the associated table*

  • 插入新数据时,外键字段只能填写关联表中已有的数据
    [En]

    when inserting new data, the foreign key field can only fill in the data that already exists in the associated table*

  • 您不能直接修改和删除关联表中的数据。如果您想要自动修改和删除数据,则需要添加额外的配置,即上面使用的级联更新和级联删除:
    [En]

    you cannot directly modify and delete the data in the associated table. If you want to automatically modify and delete the data, you need to add additional configuration, that is, cascading updates and cascading deletions used above:*

on update cascade   # 级联更新on delete cascade   # 级联删除

由于外键的实质性约束,当表很多时,外键的增加会增加耦合度。

[En]

Because of the substantial constraints of foreign keys, the increase of foreign keys will increase the degree of coupling when there are a lot of tables.

因此在实际开发项目中,有时候并不会直接使用外键创建表关系,而是通过SQL语句层面,建立逻辑意义上的表关系。

eg:操作员工表的SQL语句执行完毕之后,立刻跟着执行操作部门的SQL语句。

2.5 操作表的SQL语句补充

"""修改表名"""
      ALTER TABLE 表名 RENAME 新表名;

"""增加字段"""
      ALTER TABLE 表名 ADD 字段名  数据类型 [约束条件...],...;
      ALTER TABLE 表名 ADD 字段名  数据类型 [约束条件...]  FIRST;
      ALTER TABLE 表名 ADD 字段名  数据类型 [约束条件...]  AFTER 字段名;
"""删除字段"""
      ALTER TABLE 表名 DROP 字段名;

"""修改字段"""
      ALTER TABLE 表名 MODIFY  字段名 数据类型 [约束条件...];
      ALTER TABLE 表名 CHANGE 旧字段名 新字段名 数据类型 [约束条件...];

modify只能改字段数据类型和约束条件,不能改字段名,但是 change可以!

三、SQL查询关键字

3.1 数据准备

"""数据准备"""
create table emp(
  id int primary key auto_increment,
  name varchar(20) not null,    # 姓名
  sex enum('male','female') not null default 'male',    # 性别
  age int(3) unsigned not null default 28,  # 年龄
  hire_date date not null,  # 录用日期
  department varchar(50),       # 部门名称
  department_comment varchar(100),  # 岗位名称
  salary double(15,2),  # 薪资
  office int,    #办公室(同一部门在一件办公室)
  depart_id int  # 部门编号
);

"""插入记录"""
"""三个部门:教学,销售,运营"""
insert into emp(name,sex,age,hire_date,department,salary,office,depart_id) values
('jason','male',18,'20170301','teacher',7300.33,401,1),  # 以下是教学部
('tom','male',78,'20150302','teacher',1000000.31,401,1),
('kevin','male',81,'20130305','teacher',8300,401,1),
('tony','male',73,'20140701','teacher',3500,401,1),
('owen','male',28,'20121101','teacher',2100,401,1),
('jack','female',18,'20110211','teacher',9000,401,1),
('jenny','male',18,'19000301','teacher',30000,401,1),
('sank','male',48,'20101111','teacher',10000,401,1),
('哈哈','female',48,'20150311','sale',3000.13,402,2),  # 以下是销售部门
('呵呵','female',38,'20101101','sale',2000.35,402,2),
('西西','female',18,'20110312','sale',1000.37,402,2),
('乐乐','female',18,'20160513','sale',3000.29,402,2),
('拉拉','female',28,'20170127','sale',4000.33,402,2),
('僧龙','male',28,'20160311','operation',10000.13,403,3),  # 以下是运营部门
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬银','female',18,'20130311','operation',19000,403,3),
('程咬铜','male',18,'20150411','operation',18000,403,3),
('程咬铁','female',18,'20140512','operation',17000,403,3);

MySQL之外键、表关系及SQL查询关键字

3.2 查询关键字之 selectfrom

  • select 控制的是查询表里面的哪些字段;
select * from emp;  # 查询所有字段
select name,age from emp;  # 查询指定字段
  • from控制的是查询哪张表;

3.3 查询关键字之 where 筛选

下面通过几道练习题来帮助我们体会 where关键字的用法及其他补充知识点:

"""1.查询id大于等于3小于等于6的数据"""
select * from emp where id >= 3 and id

补充知识点:

模糊查询:没有明确的过滤条件

[En]

Fuzzy query: there are no clear filter criteria

关键字: like

关键符号:

  • %:匹配任意个数任意字符
  • _:匹配单个任意字符

示例:

show variables like '%mode%';  # 筛选出含有mode字符的结果

3.4 查询关键字之 group by 分组

也就是说,根据特定的条件将单个个体划分为一个整体。

[En]

That is, a single individual is divided into a whole according to a specified condition.

eg:按照男女将人分组、按照年龄分组、按照肤色分组……

分组之后默认只能获取到分组的依据,其他数据不能直接获取。

针对5.6版本需要自己设置sql_mode:

set global sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,PAD_CHAR_TO_FULL_LENGTH';

聚合函数:主要与分组一起使用。以下是五个常用的聚合函数:

[En]

Aggregate function: it is mainly used with grouping. Here are five commonly used aggregate functions:

max  # 最大
min  # 最小
sum  # 求和
count  # 计数
avg  # 平均

可以应用数据分组的场景:每个部门的平均工资、性别比例等。

[En]

Scenarios to which data grouping can be applied: average salary in each department, gender ratio, etc.

下面通过几道练习题来帮助我们体会 group by关键字的用法:

"""1.按部门分组"""
select * from emp group by department;  # 没设置sql_mode之前分组后取出的是每个组的第一条数据
select id,name,sex from emp group by department;  # 验证

设置 sql_modeonly_full_group_by后,意味着以后但凡分组,只能取到分组的依据,不应该再去取组里面的单个元素的值,那样的话分组就没有意义了,因为不分组就是对单个元素信息的随意获取。

set global sql_mode = "strict_trans_tables,only_full_group_by";
重新连接客户端
select * from emp group by department;  # 报错
select id,name,sex from emp group by department;  # 报错
select department from emp group by department;  # 获取部门信息

强调:只要分了组,就不能够再”直接”查找到单个数据信息了,只能获取到组名

"""2.获取每个部门的最高工资"""
以组为单位统计组内数据>>>>聚合查询(聚集到一起合成为一个结果)
select department,max(salary) from emp group by department;

您还可以在显示字段时为其设置别名:

[En]

You can also alias the field when it is displayed:

select department as '部门',max(salary) as '最高工资' from emp group by department;

as也可以省略,但是不推荐,因为语义不明确。

"""每个部门的最低工资"""
select department,min(salary) from emp group by department;

"""每个部门的平均工资"""
select department,avg(salary) from emp group by department;

"""每个部门的工资总和"""
select department,sum(salary) from emp group by department;

"""每个部门的人数"""
select department,count(id) from emp group by department;  # 统计的时候只要是非空字段,效果都是一致的
"""演示特殊情况:department_comment"""
select department,count(department_comment) from emp group by department;

补充说明:

  • group_concat:分组之后使用 如果真的需要获取分组以外的数据字段,可以使用 group_concat()
"""每个部门的员工姓名"""
select department,group_concat(name) from emp group by department;

"""每个部门的员工姓名,性别(支持自定义连接符)"""
select department,group_concat(name,'|',sex) from emp group by department;
  • concat:未分组时使用
select concat(name,sex) from emp;
select concat(name,'|',sex) from emp;

3.5 查询关键字之 having 过滤

wherehaving都是筛选功能,但是有区别:

  • where是在分组之前对数据进行筛选
  • having是在分组之后对数据进行筛选
"""筛选出员工年龄在30岁以上,且平均薪资在10000以上的部门"""
select department,avg(salary) from emp where age>30 group by department having avg(salary)>10000;

注意:

一条SQL语句的结果也可以看成是一张全新的表。

3.6 查询关键字之 distinct 去重

"""对有重复的展示数据进行去重操作 一定要是重复的数据"""
select distinct department from emp;  # 去重单个字段
select distinct id,age from emp;  # 如去重多个字段必须满足去重的字段数据都重复才能去重,否则不去重

3.7 查询关键字之 order by 排序

select * from emp order by salary asc;  # 也可不写asc,默认升序排
select * from emp order by salary desc;  # 降序排

"""先按照age降序排,在年龄相同的情况下再按照薪资升序排"""
select * from emp order by age desc,salary asc;

"""统计各部门年龄在10岁以上的员工平均工资,并且保留平均工资大于1000的部门,然后对平均工资进行降序排序"""
select department,avg(salary) from emp where age>10 group by department having avg(salary)>1000 order by avg(salary) desc;

3.8 查询关键字之 limit 分页

"""限制展示条数"""
select * from emp limit 3;

"""查询工资最高的人的详细信息"""
select * from emp order by salary desc limit 1;

"""分页显示"""
select * from emp limit 0,5;  # 第一个参数表示起始位置,第二个参数表示的是条数,不是索引位置
select * from emp limit 5,5;

3.9 查询关键字之 regexp 正则

select * from emp where name regexp '^j.*(n|y)$';

3.10 查询关键字之 exists 存在

exists关键字表示是否存在。

在使用 exists关键字时,内层查询语句不返回查询的记录,而是返回一个真假值, TrueFalse

  • 当返回 True时,外层查询语句将进行查询;
  • 当返回值为 False时,外层查询语句不进行查询。
select id,name from emp where exists (select id from emp where id > 3);  # 有结果
select id,name from emp where exists (select id from emp where id > 200);  # 内层查询无结果,所以外层查询语句不执行

Original: https://www.cnblogs.com/JZjuechen/p/15921023.html
Author: JZEason
Title: MySQL之外键、表关系及SQL查询关键字

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/507810/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • MySQL系统安装与部署

    数据库版本标准化 1.确认Supported Platforms https://www.mysql.com/support/ 2.确认安装版本 推荐:5.7.22 ,8.0.20…

    数据库 2023年5月24日
    074
  • 工程师成长阶段感悟

    从 2013 年陆续开始做软件研发工作, 去过不少公司, 做过一些类型项目, 桌面开发, web 开发, 手游开发, 端游开发, 棋牌, 视频云服务, 电商. 刚毕业那会在国企, …

    数据库 2023年6月9日
    083
  • 总监让我当小组长,我不愿意,理由竟是…

    来源:BiggerBoy作者:北哥原文链接:https://mp.weixin.qq.com/s/_pkjvDzGQUDTfo9C1bieJw 最近看到一个话题,热度很高:【总监让…

    数据库 2023年6月11日
    066
  • 如何设计一个更通用的查询接口

    临近放假,手头的事情没那么多,老是摸鱼也不好,还是写写博客吧。 今天来聊聊: 如何设计一个通用的查询接口。 首先,我们从一个简单的场景开始。现在,我需要一个订单列表,用来查询【我的…

    数据库 2023年6月6日
    095
  • 在Ubuntu系统上安装StoneDB数据库

    今天我会进行StoneDB数据库在Ubuntu 22.04系统下的安装。 严格按照官方文档的步骤操作,看看安装能否成功。 [En] Strictly follow the step…

    数据库 2023年5月24日
    097
  • 编译型语言和解释型语言

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    数据库 2023年6月6日
    0113
  • 快速入门上手Markdown

    第一次接触 Markdown是写代码初期看很多大佬的 github,他们的项目一定会有一份文件叫 Readme.md的文件他们由一些简单美观的符号和汉字字母组成,编译之后成为一篇简…

    数据库 2023年6月11日
    078
  • 基于Vue的二进制时钟组件 — fx67llBinaryClock

    fx67llClock Easy & Good Clock ! npm 组件说明 一个基于Vue的二进制时钟组件,没什么卵用,做着好玩,可以方便您装饰个人主页 使用步骤 n…

    数据库 2023年6月11日
    077
  • 类加载器ClassLoader

    1.双亲委派模型 java是根据双亲委派模型的加载类的,当一个类加载器加载类时,会先尝试委托给父类加载器去加载,直到到达启动类加载器顶层若加载不了,则再让子类加载器去加载直到类成功…

    数据库 2023年6月16日
    099
  • 事物的隔离性和MVCC

    事物的隔离性 mysql的服务端是支持多个客户端同时与之连接的,每个客户端可能还并发了好几个连接,所以mysql是需要同时处理很多事情的,每一件独立的事情就叫做事务。我们知道事务有…

    数据库 2023年5月24日
    084
  • Java 多线程共享模型之管程(下)

    共享模型之管程 wait、notify wait、notify 原理 Owner 线程发现条件不满足,调用 wait 方法,即可进入 WaitSet 变为 WAITING 状态 B…

    数据库 2023年6月16日
    096
  • Docker安装配置Oracle详细教程(以作持久化处理)

    Docker安装Oracle 1,拉取Oracle镜像,拉取成功后查看  docker pull registry.cn-ha…

    数据库 2023年6月11日
    0163
  • 9 &和&&的区别

    &运算符有两种用法 在解释按位与&之前,我们先了解一个知识:程序中的所有数在计算机内存中都是以二进制的形式存储的,位运算就是直接对内存中整数的二进制位进行操作。 按…

    数据库 2023年6月6日
    0109
  • DASCTF 冰墩墩

    SimpleFlow 一下子就能发现传了一个含有flag.txt的压缩包,需要密码,字典简单跑一下就发现是 <span class=”ne-text”>PaSsZiPW…

    数据库 2023年6月11日
    066
  • VS code 每次退出都要重新下载解决方案

    VS code 每次退出都要重新下载解决方案 打开文件-首选项-设置 在搜索栏输入Extensions: Auto Update 然后把所有打钩的取消 ,退出vs code 的时候…

    数据库 2023年6月16日
    089
  • 20 行代码!带你快速构建基础文本搜索引擎 ⛵

    💡 作者:韩信子@ShowMeAI📘 机器学习实战系列:https://www.showmeai.tech/tutorials/41📘 深度学习实战系列:https://www.s…

    数据库 2023年6月14日
    073
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球