11-1 数据库基础
1 数据库的基本概念
1.1 什么是数据库
数据库就是存储数据的仓库.本质上就是一套基于CS架构的客户端和服务器端程序.最终的数据存储在服务器端的硬盘中.
1.2 存储数据有两种方式:
- 存入内存中.
- 优点:存取速度快
- 缺点:断电即消失,无法永久保存
- 存入文件中
- 优点:永久保存
- 缺点:存取速度慢
1.3 为什么要使用数据库
直接使用文件存储会带来很多的问题.问题有:
- 存取速度慢
- 我们的程序将来可能分布在不同的机器上,如果只是在单台机器上,机器的性能肯定是有上限的,如果一台机器无法满足我们的需求,我们可以使用多台机器共同完成任务.而多台机器可以以两种方式提供服务.( 数据分布在不同的机器上,必须通过网路访问)
- 做分布式
- 每个服务器提供不同的服务(有时候某个业务流程可能会涉及到多个服务器)
- 优点:耦合度降低,易维护.
- 缺点:通讯繁琐,容灾性没有集群好
- 做集群
- 所有的服务器提供的服务是一模一样的
- 优点是 容灾性强,易扩展,可插拔
- 做分布式
- 用户权限管理
- 多个客户端并发访问,数据要保证安全
以上的几个问题,使用文件来存储,无法解决.而数据库能够解决这个问题.
1.4 数据库的分类
数据库又分为关系型数据库和非关系型数据库.
1.4.1 关系型数据库
数据之间可以存在关联关系,数据库会帮我们来维护这种关系.这类的数据库通常存储介质都是磁盘.
常见的关系型数据库有mysql,sqlserver,oracle,db2
1.4.2 非关系型数据库
这类的数据库没有能帮我们维护数据之间的关系.
通常存储介质都是内存
常见的非关系型数据库有:mongoDB,redis
1.5 数据库的重要概念
数据(column):文件中的某个字符串,
记录(row):文件中的某一行
表(table):某个文件
库(database):就是一个文件夹
DBMS:数据库管理系统,指的就是数据库软件
数据库服务器:就是指运行DBMS的计算机
2 安装数据库
可以在官方网站上下载对应版本的压缩包形式的安装包进行解压安装.
# 压缩包的目录结构(只标识出了文件夹名称)
D:\SOFTWARE\MYSQL 5.6
├─bin # 存储所有执行文件
├─data # 存储数据的位置
├─docs
├─include
├─lib
├─mysql-test
├─scripts
├─share
└─sql-bench
2.1 安装步骤
- 添加环境变量
- 将bin目录的路径加入到环境变量中
- 注册系统服务
- 安装命令
mysqld --install
- 删除命令
sc delete mysql
,注意是服务名称,不是文件名称 - 启动服务
net start mysql
- 停止服务
net stop mysql
- 查找某个进程
tasklist | findstr msyqld
,可以看到进程编号 - 杀死进程
taskkill /f /pid 进程编号
- 安装命令
- 启动完成服务后,即可通过终端进入数据库.
2.2 数据库root管理员密码的设置
修改密码可以分为两种情况,知道原始密码和不知道原始密码.
2.2.1 知道原始密码的情况
- 登陆到mysql执行更新语句来修改密码
updata mysql.uesr set password=password('新密码') where host='localhost' and user='root';
# 刷新权限
flush privileges;
# 或者重启mysql服务,使密码生效.
2. mysqladmin 小工具(举例:将密码从123改为321)
mysqladmin -uroot -p123 password 321
2.2.2 不知道原始密码的情况
- 删除权限相关的文件(不建议这样干,晚上会回不了家的)
- 跳过授权表登陆修改
# 手动启动mysqld指定参数
mysqld --skip-grant-tables
update user set password=password('新密码') where host='localhost' and user='root';
# 执行上述两行命令后,再重启mysql服务即可
3 简单的使用
3.1 连接数据库
mysql -h数据库IP -u用户名 -p密码 -P端口号
如果只使用mysql 就能进入命令行,可能是下面两种情况:
- 是以普通的游客身份进入,没有数据库的修改和查看权限
- 当前数据库没有设置root的密码,端口号默认3306未修改.这种情况多见于刚安装完数据库,建议及时修改数据库账号密码以便保证数据的安全.
3.2 退出数据库
exit或者quit
3.3 库的相关操作
# 切换数据库 ,可以不加分号
use dbname;
# 查看所有数据库
show databases;
# 查看数据库的创建语句
show create database dbname\G # \G格式化输出; # \G格式化输出
# 创建数据库
create database dbname;
create database dbname charset utf8; # 指定数据库的编码方式.避免之后存入的数据乱码,请事先指定好utf8
# 删除数据库
drop database dbname;
# 查看当前所在库
select database();
# 修改数据库编码的另外一种方式
# 可以进入到数据库文件夹中修改db.opt文件.
# 打开之后,第一行是编码,第二行是排序规则,需要和编码对应,具体可以自己在网上搜索一个
# 修改数据库名
# 如果数据库内没有创建表,没有数据.可以直接修改对应的文件夹名称,否则不建议这样操作.
3.4 命名规范
无论是数据库名/表的名称还是字段的名称,都需要遵循以下规范.
- 不区分大小写
- 不要使用关键字.
- 不能使用纯数字
- 可以使用下划线,但是通常与数字和字符组合使用,不能单独使用
3.5 表的操作
# 创建表(指定编码)
create table tbname(字段1 类型,字段2 类型...) charset utf8;
# 查看当前库下所有表
show tables;
# 查看表结构
desc tbname;
# 查看表的创建语句
show create table tbname\G; # \G格式化输出
# 删除表
drop table tbname;
# 清空表数据 重建表
truncate table tbname;
delete from tbname;# 也是删除表内的所有记录
# 修改表结构
# 添加字段
alter table tbname add 字段名 类型;
# 删除字段
alter table tbname drop 字段名;
# 修改数据类型
alter table tbname modify 字段名 新的类型
# 修改列名
alter table tbname change 旧的字段名 新的字段名 新的类型;
# 修改表的名称
rename table 旧名称 to 新名称;
# 修改编码
alter table tbname charset utf8;
# 修改字段排列位置
alter table tbname modify 字段名1 数据类型 first|after 字段2;
# 更改表的存储引擎
alter table tbname engine= 新的存储引擎;
# 删除表的外键
# 删除表的外键
alter table tbname drop foreign key 外键名;
4 配置文件的使用
配置文件需要放在安装目录的根目录,与bin同一级
比如,可以创建一个配置文件,名称叫做 my.ini
使用cfg格式,即 section+option
注意配置文件内不能使用引号
# 分区名称,也可以叫做节点
[section]
# 具体的配置项
option
# 示例
# my.ini
# 客户端配置完成后,不需要重启服务
[mysql]
user = root
password = 123
[client] # 是客户端除了mysql之外的配置.
default-character-set = utf8
# 服务器端配置,配置完成后需要重启服务
[mysqld]
character-set-server = utf8
5. 数据库引擎
什么是数据库引擎?
数据库引擎指的是 真正的负责存储数据的模块.
数据库引擎有以下几种:
- innodb
- myisam
- blackhole
- csv
- memory
- archive
...等等
不同的引擎具备不同的特点:具体使用哪一个引擎需要根据实际需求来选择.
# 查看支持的引擎
show engines;
# 创建表时指定数据库引擎
create table tbname(字段 类型) engine= XXX;
# 默认的引擎是innodb
6 数据库的增删改查
# 插入数据
# 插入单条数据
insert into tbname (字段1,字段2...) values (值1,值2...); # 前面指定多少的字段,后面就得插入多少个值
insert into tbname values (值1,值2...) # 插入的值的个数必须与该表字段数量一致并且顺序一一对应
# 同时插入多条数据
insert into tbname values (值1,值2),(值1,值2)...
# 一个查询结果插入另一张表,注意字段要对应上
insert into tbname select * from tb2;
# 查询满足条件的记录
select 字段 from 表名 where 条件;
# 更新满足条件的记录
update tbname set 字段=值,字段2=值 where 条件;
# 删除满足条件的记录
delete from tbname where 条件;
7 mysql中的数据类型
对mysql中的数据进行分类有什么好处?意义何在?
- 可以分配合适的存储空间,节省消耗
- 采用不同的操作方法,提高存取效率
- 对应不同的需求
7.1 整型
整型有以下几类:
- tinyint
- smallint
- mediumint
- int
- bigint
7.1.1 创建表时,可以设置有无符号
数据库默认情况下是以有符号的形式插入数据的.我们使用unsigned来设定无符号.
# 关于有无符号,示例如下
create table t1(id tinyint); # 默认为有符号
# 存入的数据范围为-128~127
# 设定无符号
create table t2(id tinyint unsigned)
# 此时存入的数据范围为0~255
7.1.2 设置严格模式
mysql5.6版本默认是非严格模式,
在这种情况下 如果数据超出范围,mysql会自动取最大值.
这样的话,可能存在数据丢失的情况.所以我们应该讲mysql的sql模式修改为严格模式.
# 查看当前的sql模式
select @@sql_mode; # 一个@表示全局变量, 两个@ 表示会话级变量(也可以看做局部变量)
# 临时设置sql_mode
set @@sql_mode = 'NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES'
# 想要永久设置sql_mode ,可以直接进入配置文件修改
[mysqld]
sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
7.1.3 指定长度
也就是限制数据的长度范围,如下列示例
create table t1(id int(10));
# 其中的(10) 只是说显示的长度为10个长度,但是默认情况下这个数字没有起到作用
# 要想起作用,我们可以指定zerofill
create table t1(id int(3) zerofill);
# 这种情况下 如果显示的数值不满足10个长度时,会以0补充缺失的位置,对数据没有任何影响.如上方指定的是3个长度,存入12时 ,查看数据库会发现数据变为012.
7.2 浮点型
单精度浮点数float和双精度浮点数double 都可以用来存储带小数的数值.但是都不是很精确.
如果对精度要求比较高,可以使用decimal类型
# 使用(M,D)的方式设定M(显示的总位数)和D(小数的位数)
# decimal 中M值最大65,D值最大30.
# 默认值M为10, D为0
7.3 字符串
7.3.1 char和varchar类型
char 定长字符串
varchar 长度可变的字符串
char类型的优缺点:
- 优点: 存取的速度快于varchar,因为它是固定长度,可以直接读取
- 缺点: 浪费磁盘空间.也是因为固定长度,即使存入的字符长度少于指定长度,也是按指定长度存入硬盘空间.
varchar类型的优缺点:
- 优点: 节省内存空间.可以根据存入的字符长度而变化占用的长度
- 缺点: 速度慢于char类型.长度可变导致存取速度变慢
如果字符长度不大的情况下,建议使用char类型进行存储.否则的话,可以选择varchar类型进行存储
char最大的范围为255
varchar 最大的范围为66635
如果存储的数据为字符长度超过varchar的范围,可以采用text类型,text类型最大可以存储2的32次方的长度的字符.
7.3.2 text类型
具备编码的大字符串.范围为2的32次方的长度.
7.3.3 blob类型
这是一种没有编码的大二进制类型,可以用来存储多媒体数据/视频/音频等,因为这些二进制文件一般不会直接存储在服务器,所以这种类型不是很常用.
在这里补充一个知识点:
mysql会自动将字符串后面的额空格删除,所以你的数据在存储前应该先把空格处理掉
7.4 枚举和集合
枚举是提前规定一个取值范围,你的值只能是其中一个
集合也是提前规定一个取值范围,与枚举不同的是 你的值可以是其中的一个或者多个
集合在插入数据时,多个值之间用逗号隔开,但是它们必须包含在同一个字符串内.
7.5 日期和时间
year类型
可以使用两种方式:传入2017或者17. 占一个字节空间.
mysql> show create table t2;
+-------+----------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+----------------------------------------------------------------------------------------+
| t2 | CREATE TABLE `t2` (
`time` year(4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+----------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> insert into t2 values('2017');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values('17');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t2;
+------+
| time |
+------+
| 2017 |
| 2017 |
+------+
2 rows in set (0.00 sec)
date类型
mysql> alter table t2 modify time date;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into t2 values ('2014-2-21');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values(20140221);
Query OK, 1 row affected (0.00 sec)
time类型
mysql> alter table t2 modify time time;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into t2 values(081234);
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> insert into t2 values ('8:12:34');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from t2;
+----------+
| time |
+----------+
| 08:12:34 |
| 08:12:34 |
+----------+
2 rows in set (0.00 sec)
mysql>
datetime类型
mysql> alter table t2 modify time datetime;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into t2 values ('2017-9-22 8:12:34');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values(20170922081234);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t2;
+---------------------+
| time |
+---------------------+
| 2017-09-22 08:12:34 |
| 2017-09-22 08:12:34 |
+---------------------+
2 rows in set (0.00 sec)
mysql>
timestamp类型
mysql> alter table t2 modify time timestamp;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> insert into t2 values (now());
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values ('2017-09-22 08:12:34');
Query OK, 1 row affected (0.00 sec)
mysql> insert into t2 values ('20170922081234');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t2;
+---------------------+
| time |
+---------------------+
| 2019-07-11 19:08:50 |
| 2017-09-22 08:12:34 |
| 2017-09-22 08:12:34 |
+---------------------+
3 rows in set (0.00 sec)
mysql>
now() 获取当前时间
current_time 获取当前时间
8 约束
数据库中在定义一个字段时候,我们可以添加一些条件,从而对某一个字段进行一些限制。
8.1 什么是约束,有什么作用 constraint
约束就是一种限制。
数据库的约束,就是对数据的安全性和完整性做保证。
8.2 mysql中的约束
mysql中存在以下几个常用的约束
- unique 唯一约束
- not null 非空约束
- null 可以为空
- default 默认值
- primary key 主键
- foreign key 外键
我们按照顺序依次说一下
8.2.1 unique
唯一性约束,用唯一标识一条记录。
当一个字段被unique约束时,就表示这个字段不能出现重复的值
8.2.2 not null
非空约束,当一个字段被not null约束时,就表示这个字段的值不能为空。
8.2.3 default
用于给一个字段设置默认值。
设置了默认值的话,如果我们插入一条记录的时候,不插入这个字段的值,则mysql会使用默认值代替。
需要注意的是: 唯一性约束的字段可以插入null
8.2.4 primary key
主键约束
作用与 非空+唯一约束组合使用效果一致。
主键与普通的约束的区别:
在innodb存储引擎中,主键用于组织数据(也就是说主键对于innodb引擎来说是必须要有的。如果没有手动指定主键,mysql会自动查找一个具备非空且唯一的字段作为主键。如果没有这样的字段,mysql会创建一个隐藏字段作为主键)
主键也是一个索引,而索引有加速查询的作用。如果我们在查询语句中没有使用索引字段,mysql将无法为我们的查询加速。
所以,在今后创建表的时候,我们应该怎么来设置主键呢?
如果本来的业务中就存在非空且唯一的字段,那就把它作为主键,如果没有就自己添加一个字段专门作为主键。
我们通常将主键设置为int类型,配合自增auto_increment使用,保证其唯一性。
8.2.5 foreign key
外键约束,用于指向另一个表的主键字段。
# 创建表的时候添加外键
CREATE TABLE teacher (
id INT PRIMARY KEY auto_increment,
NAME CHAR (20),
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES dept (id)
);
创建外键约束,必须现有主表再有从表。主表一般为多对一中的多的一方。
foreign key 的约束作用:
- 在从表中插入一条记录,关联了一个主表中不存在的ID时,会导致插入失败。所以必须保证外键的值必须是在主表中存在的。
- 插入数据的顺序
- 先插入主表,在插入从表的记录
- 从表更新外键时必须保证外键的值在主表中时存在的。
- 删除主表记录前,要保证从表中没哟外键关联被删除的ID
- 必须先创建主表
- 删除表也必须先删除从表
以上这么多限制,都是因为foreign key就是用来保证两张表之间的关联关系是正确的。
8.3 级联操作 cascade
当我们需要删除主表信息时,必须先删除从表中关联的数据,非常麻烦。而级联操作就可以在我们操作主表时自动的操作从表。
8.3.1 两种级联操作
8.3.1.1 级联的删除
当删除主表时自动删除从表中相关的数据
8.3.1.2 级联更新
当主表的主键更新时自动的更新关联的从表数据。
#创建表的时候指定级联操作
drop table if exists student;
create table student(
id int primary key auto_increment,
name char(20),
gender char(1),
c_id int,
foreign key(c_id) references class(id)
on update cascade
on delete cascade
);
# 级联操作可以单独使用 也可以一起使用 空格隔开即可
8.4 外键的使用
什么时候使用外键: 当表之间存在关联关系时,我们就可以使用外键来描述这种关系。
8.4.1 多对一
在创建存在一对多或者多对一的关系的两张表时,我们需要在少的一方的表中保存多的一方的ID。
8.4.2 多对多
当双方都是一对多的关系,那么两者都是多对多的关系。
针对多对多的这种关系,我们需要创建一个中间表用来保存两张表的关系。而第三张表至少具备两个字段,分别指向两张主表的主键。
第三张表的两个字段都是外键。
为了保证没有重复的关系,我们需要对第三张表的字段进行约束。
方式1:
给两个字段设置为联合唯一+非空约束
create table t_s_r(t_id int,s_id int,unique key(t_id,s_id));
方式2:
推荐将中间的关系表的两个ID作为联合主键,同时具备了唯一且非空约束
create table t_s_r(t_id int,s_id int primary key(t_id,s_id));
8.4.3 一对一关系
针对一对一关系的处理方式:
先确定先后顺序,将先存在的数据作为主表,后存在的作为从表,使两个表的ID保持一致。
方式1: 从表的ID 即使主键又是外键
方式2:从表的ID设置为外键并保证唯一
补充知识:水平分表和垂直分表
9 查询语句
9.1 补充知识
select查询语句得到的结果可以插入另一张表中
# 示例
insert into tbname values select * from tbname2 where ...
需要注意的是,查询结果的字段需要与插入表的字段保持一致,否则插入失败.
9.2 所有select的关键字
select distinct * from tbname
where
group by
having
order by
limit a,b
# 注意关键字的顺序是固定的,不能随意改变
9.2.1 where 条件
select * from tbname where...
where后面可以是:
-
比较运算符
我们可以在where条件中,进行比较.比较运算符包括>,<,>=,<=,=,!=
-
成员运算符
我们也可以在where后面使用成员运算符 in 和not in.
-
逻辑运算符
and or not 经常出现在条件判断语句中,mysql中的where语句也可以使用这几个关键字.
使用它们 的时候,需要注意以下几点:
- not 要放在表达式的前面
- and和or 放到两个表达式的中间
-
模糊查询
一个表中比如说存储了大量的人员信息,我们可以使用模糊查询的方式来匹配近似的数据.
我们可以借助% 和 _ 来完成一些匹配.
- % 表示匹配任意字符
- _ 表示一个任意的字符
9.2.3 distinct去重
怎么样的记录才算是重复记录呢?
当我们查询出的结果中所有字段全都相同时,才算是重复的记录
distinct
使用在select之后,字段名之前,可以对指定的字段进行去重
9.2.4 指定字段
select之后不仅可以使用*代替所有的字段,也可以使用其他几种.
例如:
- *表示所有字段
- 手动指定需要查询的字段
- 四则运算也能用在此处
- 聚合函数,用于统计,具体后面说明.
9.2.5 取别名
mysql中还可以为表取别名,这个比较使用,毕竟一个表的名字太长又经常需要重复写的时候,别名可以精简我们的sql语句.
举个简单的示例:
create table teacher(id int primary key auto_increment, name char(10));
create table student(
id int primary key auto_increment,
name char(10),
tid int,
foreign key (tid) references teacher(id)
);
insert into teacher values(null,'zhangsanfeng');
insert into student values(null,'wuji',1);
select a.id,a.name,b.name from student a ,teacher b where a.tid = b.id;
9.2.6 聚合函数
也就是统计函数.可以使用在字段的位置或者是在 分组的后面.
求和 sum(字段名)
平均数 avg(字段名)
最大值 max(字段名)
最小值 min(字段名)
个数 count(字段名) # 计数的时候,如果这个字段值为空,则忽略不统计
注意:
**聚合函数不能使用在where 后面.因为 where 是一行一行的读取满足条件的记录.而聚合函数是需要拿到所有的数据才能求结果.而此时,记录只读取了一行,聚合函数是错误的,不能使用在这里. **
9.2.7 group by
分组 , 也就是将一个整体按照某个特征或依据来分为不同的部分.
分组之后,我们就可以 进行统计.这也是分组的主要目的.
语法:
select xxx from tbname group by 字段名称;
需求:统计每个性别有几个人
select sex,count(*) from emp group by sex;
需求: 查询每个性别有几个 并且显示名字
select name,sex,count(*) from emp group by sex;
# mysql 5.6下 查询的结果是name仅显示该分组下的第一个
# 5.7以上则直接报错 ,5.6也可以手动开启这个功能
# 如下:
mysql> select * from emp;
+----+------+------+
| id | name | sex |
+----+------+------+
| 1 | xxx | 男 |
| 2 | ooo | 女 |
| 3 | xx1 | 男 |
| 4 | oo1 | 女 |
+----+------+------+
mysql> select sex,name from emp group by sex;
+------+------+
| sex | name |
+------+------+
| 男 | xxx |
| 女 | ooo |
+------+------+
2 rows in set (0.00 sec)
# 我们可以用group_concat 将分组之外的字段 做一个拼接 ,但是这是没有意义
# 如果要查询某个性别下的所有信息 直接使用where 即可
结论: 只有出现在了group by 后面的字段才能出现在select的后面
9.2.8 having
这个关键字用于过滤.
和where的使用有所区别,这个关键字只能使用在分组之后.
# 示例
# 求出平均工资大于500的部门信息
select dept,avg(salary) from emp group by dept having avg(salary) > 5000;
#查询 部门人数少于3的 部门名称 人员名称 人员个数
select dept,group_concat(name),count(*) from emp group by dept having count(*) < 3;
9.2.9 order 排序
知识点:
- 查询语句默认排序为升序 ASC
- DESC 改为降序
- 按照多个字段排序时,如果第一个字段相同时,再按照第二个字段进行排序.
9.2.10 limit
用于限制要显示的记录数量
两种使用语法:
- limit 个数
- limit 起始位置,个数
这个limit可以做分页功能.
# 1. 每一页显示的条数为 a
# 2. 当前页数为 b
# 3. 起始位置 为 c = (b-1)* a
9.3 子查询
就是将一个查询语句的结果作为另一个查询语句的条件或是 数据来源.
子查询中也有几个常用的关键字: in / exists
9.3.1 in关键字子查询
当内层查询的结果有多个时,不能使用=号,必须使用in.
子查询的思路:
- 先分析查到最终的数据 到底有哪些步骤
- 根据步骤写出对应的sql语句
- 把上一个步骤的sql语句丢到写一个sql语句中作为条件.
9.3.2 exists 关键字子查询
当内存查询有结果时,外层才会执行.
# 案例:
select* from dept where exists (select * from dept where id = 1);
# 由于内层查询产生了结果 所以 执行了外层查询dept的所有数据
9.4 多表查询
9.4.1 笛卡尔积查询
这个查询会将两张表进行水平拼接,列出所有的组合的可能性.
select * from t1,t2;
- 笛卡尔积查询的结果会出现大量的错误数据
- 并且会产生重复的字段信息.
9.4.2 内连接查询 inner join
本质上就是笛卡尔积查询.
我们可以在查询的时候,加上on条件,筛选出我们想要的结果.
# 语法:
select * from t1 inner join t2 on ...;
# 这里的inner可以忽略不写.
9.4.3 左外连接 left join
左边的表无论是否能够匹配都要完整显示,右边的仅展示匹配上的记录.未匹配上的记录 字段为null
9.4.4 右外连接 right join
右边的表无论是否能够匹配都要完整显示,左边的仅展示匹配上的记录.未匹配上的记录 字段为null
左外连接也可以实现右外连接,将两个表的位置互换即可.反之亦然.
9.4.5 全外连接查询
无论是否匹配成功,两边表的数据都要全部显示.
我们可以将 左外连接 查询的结果 和右外连接 查询的结果做一个合并,使用union
select * from emp left join dept on dept_id = dept.id
union
select * from emp right join dept on dept_id = dept.id;
上述使用了union,需要注意的是:
- union 会自动去除重复的记录
- union all 不会去重
使用union 时,必须保证两个查询结果,列数相同.一般用在多个查询结果结构完全一致时.
总结:
内连接 只显示匹配成功的记录
外连接 没有匹配成功的也要实现