MySQL 约束、表连接、表关联、索引
一、外键:
- 1、什么是外键
- 2、外键语法
- 3、外键的条件
- 4、添加外键
- 5、删除外键
1、什么是外键:
主键:是唯一标识一条记录,不能有重复的,不允许为空,用来保证数据完整性。
外键:是另一表的唯一性字段, 外键可以有重复的, 可以是空值,用来和其他表建立联系用的。所以说,如果谈到了外键,一定是至少涉及到两张表。例如下面这两张表:
上面有两张表:部门表(dept)、员工表(emp)。Id=Dept_id,而Dept_id就是员工表中的外键:因为员工表中的员工需要知道自己属于哪个部门,就可以通过外键Dept_id找到对应的部门,并且能找到部门表里的各种字段信息,从而让二者相关联。
所以说,外键一定是在从表中创建(特定新加的字段用来做外键),从而找到与主表之间的联系;从表负责维护二者之间的关系。
我们先通过如下命令把部门表和职工表创建好,方便后面的举例:
create table department(
id int primary key auto_increment,
name varchar(20) not null,
description varchar(100)
);
create table employee(
id int primary key auto_increment,
name varchar(10) not null,
gender varchar(2) not null,
salary float(10,2),
age int(2),
gmr int,
dept_id int
);
然后把两张表的数据填好,显示效果如下:
部门表:
员工表:
2、外键的使用需要满足的条件
1. 两张表必须都是InnoDB表,并且它们没有临时表。
(注:InnoDB是数据库的引擎。MySQL常见引擎有两种:InnoDB和MyISAM,后者不支持外键。)
2. 两张表的关联字段必须具有相似的InnoDB内部数据类型。
3. 建立外键关系的从表字段必须建立了索引(创建外键时自动建立默认索引)。
问:你的数据库用什么存储引擎?区别是?
答案:常见的有InnoDB和MyISAM。
InnoDB:支持外键约束,支持事务。对索引都是单独处理的,无需引用索引。
MyISAM:不支持外键约束。不支持事务。对数据大批量导入时,它会边插入数据边建索引,所以为了提高执行效率,应该先禁用索引,在完全导入后再开启索引。
3、添加外键的语法:
有两种方式:
- 方式一:在创建表的时候进行添加
- 方式二:表已经创建好了,继续修改表的结构来添加外键
【方式一】在创建表的时候进行添加
[constraint 外键标识] foreign key [id](从表的字段1) references tbl_name(主表的字段2)
[on delete {restrict| cascade| set null | no action}]
[on update {restrict | cascade | set null | no action}
上面的代码是同一行,中括号里的内容是可选项。
解释如下:
Constraint:约束
可以给这个外键约束起一个名字,有了名字,以后找到它就很方便了,如果不加此参数的话,系统会自动分配一个名字。包含以下约束内容:
1.主键约束;
2.外键约束 ;
3.唯一约束(unique);
4.检查约束(check,即取值范围,MySQL貌似无此约束);
5.非空约束(not null,如"alter table tname modify colname varchar(64) not null"修改字段即可)。
【例】增加约束:alter table `user` add constraint [name_uniq] unique(`name`);
alter table `user` add constraint [sex_check] check(sex='男' OR sex='女' OR sex='未知');
删除约束:alter table table_name drop constraint_name;
foreign key:将从表中的字段1作为外键的字段。
references:映射到主表的字段2。
on delete 后面的四个参数:代表的是当删除主表的记录时,所做的约定。
- restrict(限制):如果你想删除的那个主表,它的下面有对应从表的记录,此主表将无法删除。
- cascade(级联):如果主表的记录删掉,则从表中相关联的记录都将被删掉。
- set null:将外键设置为空。
- no action:什么都不做。
注:一般是restrict和cascade用的多。
【方式二】表已经创建好了,继续修改表的结构来添加外键。
我们在第一段中内容中已经将表建好了,数据也填充完了,现在来给从表(员工表)添加外键,让它与主表(部门表)相关联。代码举例如下:
alter table employee add foreign key(dept_id) references department(id) on delete cascade;
代码解释:
alter table employee:在从表employee中进行操作;
add foreign key(dept_id):将从表的字段dept_id添加为外键;
references department(id):映射到主表department当中为id的字段。
运行上方代码后,我们通过navicat来看一下外键有没有添加成功:
上图中,选中表employee,单击红框部分的“设计表”按钮,界面如下:
上图中就可以看到我们新建的外键了,而且系统默认给这个外键起了个名字:employee_ibfk_1。默认规则是RESTRICT。紧接着来给外键设置值:
上图中,我们打开员工表,然后给外键设置值,1代表宣传部,2代表秘书部。
然后我们回到主表(部门表),此时如果想删除id为1的宣传部,会弹出如下提示:(因为外键的默认规则为restrict)
4、删除外键:(通过sql语句的方式)
我们在navicat中可以通过图形界面的方式删除外键,也可以通过sql语句来删除。
(1)获取外键名:
如果在命令行中不知道外键的名字,可以通过查看表的定义找出外键的名称:
show create table emp;
运行效果如下:
其实我们在表的信息中也可以看到:(注意书写命令的格式)
(2)删除外键:
alter table employee drop foreign key 外键名;
二、表连接(join)
我们以下面的两张表举例:作为本段内容的例子
department部门表:
employee员工表:
其中,外键对应关系为:employee.dept_id=department.id。employee.leader中的数字的含义为:生命壹号的leader是生命二号,生命二号没有leader,生命叁号的leader是生命壹号。
1、内连接(默认):
只列出匹配的记录。
语法:
select … from table1 [inner] join table2
[on condition]
where definition
解释:只列出这些连接表中与连接条件相匹配的数据行。INNER可以不写,则默认为内连接。[ON condition]里面写的是连接的条件。
举例:
select e.name,d.name from employee e inner join department d on e.dept_id=d.id;
等价于:
select e.name,d.name from employee e,department d where e.dept_id=d.id;
运行效果:
2、外连接:
外连接分类:
- 左外连接(left [outer] join)
- 右外连接(right [outer] join)
- 全外连接(full [outer] join) --(注:MySQL暂不支持)
语法:
select … from table1
(left | right | full) [outer] join table2
on condition
where definition
解释:
不仅列出与连接条件(on)相匹配的行,还列出左表table1(左外连接)、或右表table2(右外连接)、或两个表(全外连接)中所有符合WHERE过滤条件的数据行。一般都是用左连接或者外连接。
其中,[outer]部分可以不写,(left | right | full)部分要写其中一个。
2.1 左外连接:左表列出全部,右表只列出匹配的记录。
举例:
2.2 右外连接:右表列出全部,左表只列出匹配的记录。
举例:
3、交叉连接(笛卡尔积):
语法:
select … from table1 cross join table2;
没有on子句和where子句,它返回的是连接表中所有数据行的笛卡尔积。
笛卡尔积举例:假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}
其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
等价于:
select … from table1, table2;
举例:
4、自连接:
参与连接的表都是同一张表(通过给表取别名虚拟出两张表)。
注:非常重要,在JavaWeb中的目录树中用的特别多。
举例:查询出员工姓名和其leader的姓名(类似于求节点及其父节点)
我们来详细解释一下上面的代码。对于同一张employee表,我们把e1作为员工表,e2作为领导表。首先把全部的员工列出来(基于左外连接),然后找到我们所需要的条件:员工的经理id(e1.leader)等于经理表的id(e2.id)。
举例:查询出所有leader的姓名。
分析的道理同上。
其实,上面的两个查询结果都是下面这个查询结果的一部分:
三、子查询:
作用:某些情况下,当进行查询的时候,需要的条件是另外一个select 语句的结果,这个时候,就要用到子查询。
定义:为了给主查询(外部查询)提供数据而首先执行的查询(内部查询)被叫做子查询。也就是说,先执行子查询,根据子查询的结果,再执行主查询。
关键字:用于子查询的关键字主要包括 IN、NOT IN、EXIST、NOT EXIST、=、<>等(符号“<>”的意思是:不等于)。
备注:MySQL从4.1开始才支持SQL的子查询。一般说子查询的效率低于连接查询(因为子查询至少需要查询两次,即至少两个select语句。子查询嵌套越多,性能越低)。表连接都可以用子查询替换,但反过来说却不一定。
我们一下面的这张员工表举例:
1、举例:查询月薪最高的员工的名字
上面的例子中,我们就是先通过聚合函数查出最高的月薪,然后根据这个值查出对应员工的名字。
2、举例:查询出每个部门的平均月薪
上面的例子中,先将部门进行分类(前提是部门不能为空),然后分别单独求出各类中的薪水平均值。
注:这里我们没有用到子查询,因为比较麻烦。
3、举例:查询月薪比平均月薪高的员工的名字(我们知道,整体的平均工资是250)
疑问:如果要查询比部门平均工资高的员工,该怎么写呢?下面的这种写法是错误的:
四、表关联
关联表之间的关系:一对多,多对多(需中间表),一对一。
被关联字段永远是唯一的,关联字段则不一定。
1、一对多(最常用)
A表中唯一一条记录对应B表中多条记录。“一”的一方是主表(被关联表),“多”的一方是从表(关联表),因此外键设在“多”的一方。
需要关心的:1.保证主表被关联的字段必须唯一(主键或unique约束);
2.保证从表关联字段必须可以重复。
关联方法:在从表(关联表)加一个字段,将其设为外键指向主表唯一性字段。注意二者类型一致。
例:
#===被关联的表===
create table press(
id int primary key auto_increment,
name char(20),
);
#===关联的表===
create table book(
book_id int primary key auto_increment,
book_name varchar(20),
book_price int,
press_id int, #增加1个字段,设为外键
constraint Fk_pressid_id foreign key(press_id) references press(id) on delete cascade on update cascade
);
2、多对多
A表中唯一一条记录对应B表中多条记录,反之亦然。如一个作者可以写多本书,一本书也可以有多个作者,双向的一对多,即多对多。
需要关心的:1.保证A、B表被关联字段必须唯一(主键或unique约束);
2.新建一张表,保存A、B表的被关联字段,并且保证新表中的关联字段也必须唯一(主键或unique约束)。
关联方法:在新表中,增加两个字段,作为联合主键或联合唯一,再将该两个字段分别设为外键指向A、B表的唯一性字段。注意类型一致。
例:
#===被关联的表===
create table book1(
id int primary key auto_increment,
name varchar(10),
price float(3,2),
);
#====被关联的表===
create table author(
id int primary key auto_increment,
name char(5),
);
#===关联的表===
create table author2book(
id int primary key auto_increment,
book_id int not null,
author_id int not null, #增加2个字段,联合唯一约束,再分别设为外键
unique(book_id,author_id),
foreign key(book_id) references book1(id) on delete cascade on update cascade,
foreign key(author_id) references author(id) on delete cascade on update cascade
);
3、一对一(最少用)
A表和B表的记录最多是一一对应。通常用在数据分割(分割出来的字段肯定和原表字段数据一致)。如用户和管理员(只有管理员才可以登录,一个管理员对应一个用户)。
需要关心的:1.保证主表中的被关联字段必须唯一(主键或unique约束);
2.保证从表中的关联字段也必须唯一(主键或unique约束),这是与“一对多”的区别之处。
关联方法:在从表(关联表)加一个字段,必须设为唯一(主键或unique约束),再将其设为外键指向主表唯一性字段。注意二者类型一致。
例:
#===被关联的表===
create table user(
id int primary key auto_increment,
name char(10),
);
#===关联的表===
create table admin(
id int primary key auto_increment,
user_id int unique, #增加1个字段,设为唯一(区别于“一对多”),再设为外键
password varchar(16),
foreign key(user_id) references user(id) on delete cascade on update cascade
);
五、索引
主要内容如下:
- 1、索引的概念
- 2、普通索引
- 3、唯一索引
- 4、主键索引
- 5、全文索引
- 6、删除、禁用索引
- 7、设计索引的原则
关于索引,推荐的学习链接:
http://www.cnblogs.com/hustcat/archive/2009/10/28/1591648.html(大牛)
http://blog.csdn.net/cuidiwhere/article/details/8452997
http://www.cnblogs.com/cq-home/p/3482101.html
1、索引的概念
索引是数据库中用来提高查询性能的最常用工具。
所有MySQL列类型都可以被索引,对相关列使用索引是提高SELECT操作性能的最佳途径。索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。
在使用以下操作符时,都会用到相关列上的索引:
- >、<、>=、<=、<>、in、 between
- like 'pattern'(pattern不能以通配符开始,即通配符不能放前面,即使放在了前面,索引也无效)
注:索引的值因为不断改变,所以是它需要维护的。如果数据量较少,建议不用索引。
2、normal 普通索引(第一种索引)
- 方式一:直接创建索引:
语法,注意加():
CREATE INDEX 索引名 ON 表名(列名[(length)]…);
举例:
然后,我们在表中可以看到新创建的索引:(我们可以在这个navicat的可视化界面中修改索引类型)
- 方式二:修改表时添加索引
语法:
ALTER TABLE 表名 ADD INDEX [索引名] (列名[(length)]…);
- 方式三:创建表的时候指定索引:
CREATE TABLE 表名 ( 表名 (
[...],
INDEX [索引名] (列名[(length)]…);
注意:如果要创建索引的列的类型是CHAR、VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定length。
3、unique 唯一索引(第二种索引)
这种索引和前面的“普通索引”基本相同,但有一个区别:索引列的所有值都必须唯一。例如可以将身份证号作为索引。
创建方式和上方的普通索引类似。即:将普通索引的“index”改为“unique index”。
4、主键索引(一种特殊的唯一索引)
主键是一种特殊的唯一索引,一般在创建表的时候指定。在 MYSQL 中,当你建立主键时,主键索引同时也已经建立起来了,不必重复设置。
记住:一个表只能有一个主键,也即只有一个主键索引。
5、fulltext index全文索引(第三种索引)
MySQL从3.2版开始支持全文索引和全文检索。在MySQL中,全文索引的索引类型为fulltext index。
MySQL5.0版本只有MyISAM存储引擎支持fulltext index,并且只限于CHAR、VARCHAR和TEXT类型的列上创建。
注:全文索引维护起来很吃力,所以了解即可。
创建方式和上方的普通索引类似。即:将普通索引的“index”改为“fulltext index”。
6、删除、禁用索引
一般使用“删除”,不使用“禁用”。
删除索引:
语法:
DROP INDEX 索引名 ON 表名
对于MyISAM表在做数据大批量导入时,它会边插入数据边建索引。所以为了提高执行效率,应该先禁用索引,在完全导入后,再开启索引。而InnoDB表对索引都是单独处理的,无需禁用索引。
禁用索引:
ALTER TABLE 表名 DISABLE KEYS;
打开索引:
ALTER TABLE 表名 ENABLE KEYS;
7、设计索引的原则
- 最适合索引的列是出现在WHERE子句中的列,或连接子句(on语句)中指定的列,而不是出现在SELECT后的列。
- 索引列的值中,不相同的数目越多,索引的效果越好。
- 使用短索引:对于CHAR和VARCHAR列,只用它的一部分来创建索引,可以节省索引空间,也会使查询更快捷。
如:CREATE INDEX part_of_name ON employees(name(10)); 这个句子中指定的length长度为10,就是使用短索引,也就是说取name的前十个字符。
- 利用最左前缀。
- 根据搜索的关键字建立多列索引。
- 不要过度索引。维护索引需要成本。
至此。转载请注明出处。
MySQL 约束、表连接、表关联、索引的更多相关文章
- C# LINQ Join两个表连接,关联多个条件的写法
1.sql语句: select * from Users u join Teachers t on u.UserID==t.TeacherID and u.Name=t.Name 2.linq写法: ...
- 3.mysql小表驱动大表的4种表连接算法
小表驱动大表 1.概念 驱动表的概念是指多表关联查询时,第一个被处理的表,使用此表的记录去关联其他表.驱动表的确定很关键,会直接影响多表连接的关联顺序,也决定了后续关联时的查询性能. 2.原则 驱动表 ...
- 看懂Oracle执行计划、表连接方式
看懂Oracle执行计划 原文:https://www.cnblogs.com/Dreamer-1/p/6076440.html 最近一直在跟Oracle打交道,从最初的一脸懵逼到现在的略有所知,也 ...
- SqlServer索引、优化、约束、连接
索引的创建和删除 create index in_name on person(name) --创建索引 drop index person.in_name --删除索引 create index i ...
- SQL中的笛卡儿积问题和多表连接操作
(使用scott用户) SELECT * FROM scott.dept;--4SELECT * FROM scott.emp;--14 /**笛卡尔积内连接(等值连接)外连接(非等值连接)自连接*/ ...
- MySQL数据库学习笔记(六)----MySQL多表查询之外键、表连接、子查询、索引
本章主要内容: 一.外键 二.表连接 三.子查询 四.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复 ...
- MySQL多表查询之外键、表连接、子查询、索引
MySQL多表查询之外键.表连接.子查询.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复的,不允许为 ...
- MySQL数据库学习笔记----MySQL多表查询之外键、表连接、子查询、索引
本章主要内容: 一.外键 二.表连接 三.子查询 四.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复 ...
- mysql学习笔记-- 多表查询之外键、表连接、子查询、索引
本章主要内容: 一.外键 二.表连接 三.子查询 四.索引 一.外键: 1.什么是外键 2.外键语法 3.外键的条件 4.添加外键 5.删除外键 1.什么是外键: 主键:是唯一标识一条记录,不能有重复 ...
随机推荐
- 【原】以setTimeout来聊聊Event Loop
平时的工作中,也许你会经常用到setTimeout这个方法,可是你真的了解setTimeout吗?本文想通过总结setTimeout的用法,顺便来探索javascript里面的事件执行机制. setT ...
- windows系统下发布python模块到pypi
1. 在pypi.python.org网站注册一个用户,记住用户名和密码. 2. 编写需要上传模块的源代码,文件名为:skyersfirstpythonmodule.py 3. 新建文件夹,名称为sk ...
- 04 Tensorflow的中的常量、变量和数据类型
打开Python Shell,先输入import tensorflow as tf,然后可以执行以下命令. Tensorflow中的常量创建方法: hello = tf.constant('Hello ...
- Mysql加锁过程详解(5)-innodb 多版本并发控制原理详解
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- shell脚本示例:批量比较多个文件的内容是否相同
bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html 要比较两个文件的内容是否完全一致,可以简单地使用diff命令. ...
- Go Web:RESTful web service示例
RESTful架构的简介 web服务的架构模式主要有2种:SOAP和REST.SOAP和REST都回答了同一个问题:如何访问web服务. SOAP风格的程序是功能驱动的,要借助xml来传递数据,明确表 ...
- C#异常处理。
一.什么是异常? 程序运行时发生的错误. 二.异常处理的一般代码模式. try{..可能发生异常的代码} catch{..对异常的处理} finally{...无论是否发生异常.是否捕获异常都会执行的 ...
- 应用TortoiseGit为github账号添加SSH keys,解决pull总是提示输入密码的问题
每次同步或者上传代码到githun上的代码库时,需要每次都输入用户名和密码,这时我们设置一下SSH key就可以省去这些麻烦了.若果使用TortoiseGit作为github本地管理工具,Tortoi ...
- c# 解密微信encryptedData字段
参考链接:https://www.cnblogs.com/jetz/p/6384809.html 我写了一个工具方法,直接照搬链接中的方法,还有一个工具类. public class Encrypt ...
- stringMVC_09文件批量上传
一.思路 在文件上传的基础上引入数组可以实现批量上传,只需要更改一下前段页面和controller类即可 文件上传: https://www.cnblogs.com/aihuadung/p/10167 ...