全网最全MySQL知识点万字整理

1,254 阅读34分钟

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

一、SQL介绍

1.1、SQL概述

    人和人交流需要语言,人和数据库交流也需要语言,而这个专门特定为程序员和数据库打交道的语言就是 SQL 语言。

    SQL:结构化查询语言(Structured Query Language)。是关系型数据库标准语言。 特点:简单,灵活,功能强大。

1.2、SQL包含的6个部分

1.2.1、数据查询语言(DQL)

    其语句,也称为“数据检索语句”,用以从表中获得数据,确定数据怎样在应用程序给出。保留字 SELECT 是DQL(也是所有SQL)用得最多的动词,其他DQL常用的保留字有WHEREORDER BYGROUP BYHAVING。这些 DQL 保留字常与其他类型的SQL语句一起使用。

1.2.2、数据操作语言(DML)

    其语句包括动词 INSERTUPDATEDELETE。它们分别用于添加,修改和删除表中的行。也称为动作语言。

1.2.3、数据定义语言(DDL)

    其语句包括动词 CREATE 和 DROP。在数据库中创建新表或删除表(CREAT TABLE DROP TABLE);为表加入索引等。DDL包括许多与人数据库目录中获得数据有关的保留字。它也是动作查询的一部分。

1.2.4、事务处理语言(TPL)

    它的语句能确保被DML语句影响的表的所有行及时得以更新。TPL语句包括BEGIN TRANSACTIONCOMMITROLLBACK

1.2.5、数据控制语言(DCL)

    它的语句通过GRANTREVOKE获得许可,确定单个用户和用户组对数据库对象的访问。某些RDBMS可用GRANTREVOKE控制对表单个列的访问。

1.2.6、指针控制语言(CCL)

    它的语句,像DECLARE CURSORFETCH INTOUPDATE WHERE CURRENT用于对一个或多个表单独行的操作。

1.3、书写规则

  1. 数据库中,SQL 语句大小写不敏感. 如: select、SELECT.、SeleCt,为了提高可读性,一般关键字大写,其他小写
  2. SQL 语句可单行或多行书写,用分号来分辨是否结束。
  3. 合理利用空格和缩进使程序易读

二、表和ORM

2.1、表

​     二维表是 同类实体 的各种 属性的集合,每个实体对应于表中的一行,在关系中称为元组,相当于通常的一条记录; 表中的列表示属性,称为Field,相当于通常记录中的一个数据项,也叫列、字段。 行: 表示一个实体,一条记录 列: 字段,数据项。

2.2、表和对象的关系(ORM)

​ ORM: Oject Reraltional Mapping : 对象表的映射

​     在开发中,我们需要将表中的数据查询出来保存到内存中,或者把内存中的数据保存到数据库中,此时就需要将数据表的数据和Java中的对象进行映射关联起来。这种映射关联就称为 ORM 思想。

在这里插入图片描述 在这里插入图片描述

三、MySQL服务

3.1、MySQL服务

​ 打开数据库连接之前:一定要保证 MySQL 服务已经开启了。

net start命令开启一个服务,如:net start MySQL。

net stop 命令关闭一个服务器,如:net stop MySQL

3.2、连接MySQL

方式一

​ 进入 MySQL 自带的客户端, 在命令行中输入密码。

方式二

​ 在运行(win + r 进入cmd )中输入命令。

格式:mysql -u账户 -p密码 -h数据库服务器安装的主机 -P数据库端口

mysql -uroot -padmin -h127.0.0.1 -P3306

    若连接的数据库服务器在本机上,并且端口是 3306。 则可以简写: mysql -uroot -padmin。

四、数据库基础

4.1、数据库基本操作

  1. 查看数据库服务器存在哪些数据库.:SHOW DATABASES
  2. 使用指定的数据库.:USE database_name
  3. 查看指定的数据库中有哪些数据表:SHOW TABLES
  4. 创建指定名称的数据库.:CREATE DATABASE database_name
  5. 删除数据库:DROP DATABASE database_name

4.2、存储引擎

    MySQL 中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供不同的功能和能力。 通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能。

​     简单来说,存储引擎是表的存储方式。

​     MySQL常用存储引擎:

  • MyISAM:拥有较高的插入,查询速度,但不支持事务,不支持外键。
  • InnoDB:支持事务,支持外键,支持行级锁定,性能较低。最安全

    InnoDB 存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但对比MyISAM,处理效率差,且会占用更多的磁盘空间以保留数据和索引。一个系统,特别是金融系统,没有事务是很恐怖的事情,一般都要选择 InnDB。

在这里插入图片描述

五、MySQL列的常用类型

5.1、最常用的类型

MsSQLJava
INTint
BIGINTlong
DECIMALBigDecimal
DATE/DATETIMEjava.util.Date
VARCHARString

5.2、整数类型

    整数类型有宽度指示器,作用是指定位宽。

    例如:某字段类型为 INT(3),保证少于3个值,从数据库检索出来时能够自动地用 0 填充,需设置填充,默认不填充。

宽度指示器不影响列存值得范围。一般不指定位宽。 20201230114133531 .png)]

5.3、小数 类型

FLOAT[(s,p)] DOUBLE[(s,p)]: 小数类型,可存放实型和整型 ,精度 (p) 和范围 (s)。

DECIMAL : 高精度类型,金额货币优先选择。

在这里插入图片描述

5.4、字符类型

  • ​ char(size) : 定长字符,0 - 255字节,size 指 N 个字符数,若插入字符数超过设定长度,会被截取并警告。
  • ​ varchar(size): 变长字符,0 - 255字节,从 MySQL5 开始支持 65535 个字节,若插入字符数超过设定长度,在非严格模式下会被截取并警告。

在这里插入图片描述

    一般存储大量的字符串,比如文章的纯文本,可以选用 TEXT 系列类型,这个系列都是变长的。

    注意: 在 MySQL 中,字符类型必须指定长度,值要使用 单引号引起来。 相当于Java中字符(String,StringBuilder/StringBuffer); 在这里插入图片描述

5.5、日期类型

    常用日期和时间类型: DATE、DATETIME。

    注意: 在 MySQL 中,日期时间值使用单引号引起来。 相当于 Java中 Date,Calender。

在这里插入图片描述

5.6、二进制类型

    二进制类型主要用于存放图形、声音和影像,二进制对象,0-4GB。

    开发中,我们一般存储二进制文件保存路径,所以以上的类型非特殊需求不会使用。

    BIT,一般存储 0 或 1,存储是 Java 中的 boolean/Boolean 类型的值(需要使用)。

在这里插入图片描述

六、表的操作(DDL)

    表的操作主要是使用 DDL 来创建表和删除表等操作

6.1、创建表

6.1.1、语法

CREATE TABLE 表名 (
	列名1 列的类型 [约束],
	列名2 列的类型 [约束],
	....
	列名N 列的类型 约束
);
-- 注意:最后一行没有逗号

6.1.2、例子

    创建一张学生表(t_student) 有id、name、email、age。

CREATE TABLE t_student (
	id BIGINT,
	name VARCHAR(15),
	email VARCHAR(25),
	age INT
);

6.1.3、注意

    创建表时,不能使用 MySQL 的关键字、保留字。

    解决办法:

# 1. 尽量避免使用关键字,可以使用其他的单词或单词组合来代替。
# 2. 一般情况下,创建表的时候习惯使用 t_ 做表名的开头。
# 3. 使用反引号(``) 将表名括起来就 ok  (`order`)。

6.2、删除表

6.2.1、语法

DROP TABLE 表名;

6.2.2、例子

-- 删除订单表
DROP TABLE `order`;

6.2.3、注意

    如果表名是数据库的关键字或保留字需要加上反引号 (`)

6.3、表的复制和批量插入

6.3.1、表的复制

    表的复制本质上是将查询结果当做表创建出来。

create table 表名 as select语句;

6.3.2、表的批量插入

    表的批量插入本质上是将查询结果插入到另一张表中。

insert into dept1 select * from dept;

6.5、表的约束

    约束是为了保证表中的数据的合法性、有效性和完整性,我们一般对表会有约束。

  1. 非空约束:NOT NULL,不允许某列的内容为空。
  2. 设置列的默认值:DEFAULT。
  3. 唯一约束:UNIQUE,在该表中,该列的内容必须唯一。
  4. 主键约束:PRIMARY KEY, 非空且唯一。
  5. 主键自增长:AUTO_INCREMENT,从 1 开始,步长为 1。
  6. 外键约束:FOREIGN KEY,A表中的外键列. A表中的外键列的值必须参照于B表中的某一列(B表主 键)。

6.5.1、主键约束

    主键值是这行记录在这张表中的唯一标识,就如同身份证号。一张表的主键约束只能有一个。

主键约束(primary key)不能重复且不能为NULL。

6.5.1.1、主键的分类

  1. 业务主键:使用有业务含义的列作为主键 (不推荐使用);
  2. 自然主键:使用没有业务含义的列作为主键 (推荐使用);

6.5.1.2、如何设计主键

    对于主键,我们有以下两种的主键设计原则:

  1. 单字段主键,单列作为主键,建议使用。
  2. 复合主键,使用多列充当主键,不建议。

6.5.1.3、结论

    使用单字段的自然主键。

6.5.1.4、例子

    创建学生表,id为主键自增,name唯一,email不为空,age默认18。

-- 移除存在的表
DROP TABLE IF EXISTS `t_student`;
	CREATE TABLE t_student(
	id BIGINT PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(25) UNIQUE,
	email VARCHAR(25) NOT NULL,
	age INT DEFAULT 18
);

6.5.2、外键约束(foreign key)

    **外键是另一张表的主键。**例如员工表与部门表之间就存在关联关系,其中员工表中的部门编号字段就是外键,是相对部门表的外键。

    外键可以为NULL,且不一定是另一张的主键,但是必须具有唯一性,一般情况下会引用另一张表的主键。

create table t_student(
	sno it,
    sname varchar(255),
    classno ,int
    foreign key (classno) references t_class(no) -- 对t_student的classno字段添加外键约束,引用的是t_calss的no字段
);

6.5.3、唯一性约束(unique)

    唯一约束修饰的字段具有唯一性,不可以重复,但是可以为NULL,也可以同时为NULL。

create table t_user(
	id int,
    username varchar(255) unique,-- 列级约束
    pwd varchar(255)
)

    我们也可以同时给两个列或者多个列添加唯一约束。

-- 这样表示两个字段连起来不能重复,两个字段添加一个约束。表级约束
create table t_user(
	id,int,
    username varchar(255),
    pwd varchar(255),
    unique(username,pwd)
)
-- 这样表示两个字段都不能重复,两个字段加两个约束。
create table t_user(
	id,int,
    username varchar(255) unique,
    pwd varchar(255) unique
)

6.6、表与表之间的关系

6.6.1、一对一

    例如t_person表和t_card表,即人和身份证。这种情况需要找出主从关系,即谁是主表,谁是从表。人可以没有身份证,但身份证必须要有人才行,所以人是主表,而身份证是从表。设计从表可以有两种方案:

  1. 在t_card表中添加外键列(相对t_user表),并且给外键添加唯一约束;

  2. 给t_card表的主键添加外键约束(相对t_user表),即t_card表的主键也是外键。

6.6.2、一对多(多对一)

    一对多(多对一):最为常见的就是一对多!一对多和多对一,这是从哪个角度去看得出来的。t_user和t_section的关系,从t_user来看就是一对多,而从t_section的角度来看就是多对一!这种情况都是在多方创建外键!

6.6.3、多对多

    例如t_stu和t_teacher表,即一个学生可以有多个老师,而一个老师也可以有多个学生。这种情况通常需要创建中间表来处理多对多关系。例如再创建一张表t_stu_tea表,给出两个外键,一个相对t_stu表的外键,另一个相对t_teacher表的外键。

七、DML增删改操作

    DML是数据操作语句,用户对表的数据进行操作,所有的DML操作都有一个受影响的行,表示SQL执行,操作了多少行数据。

7.1、插入操作

7.1.1、语法

INSERT INTO 表名 (列1,列2,列3...) VALUES(值1,值2,值3...);

7.1.2、例子

-- 1.插入完整数据记录
INSERT INTO t_student(name,email,age) VALUES('xiaoming','xiao@',18);
-- 2.插入数据记录一部分
INSERT INTO t_student(name,age) VALUES('xiaodong',19);
-- 3.插入多条数据记录(MySQL特有)
INSERT INTO t_student(name,email,age) VALUES('xiaohong','hong@',17),
('xiaohong2','hong2@',17),('xiaohong3','hong@3',17)
-- 4.插入查询结果
INSERT INTO t_student(name,email,age) SELECT name,email,age FROM t_student

7.1.3、注意

    一次插入操作只插入一行,插入多条数据为 MySQL 特有语法(不推荐使用,Mybatis有循环来批量加入)

7.2、修改操作

7.2.1、语法

UPDATE 表名
SET1 =1, 列2 =2, column3 = value3...
WHERE [条件]

7.2.2、练习

-- 将张三改为西门吹水
UPDATE t_student SET name='西门吹水' WHERE name='张三';
-- 将 id 为3 的 name 改为叶孤城,email 改为ye@,age 改为100
UPDATE t_student SET name='叶孤城' WHERE id=3;

7.2.3、注意

  1. 如果省略了条件,那么整张表的数据都会被修改,所以一般都会带上条件
  2. 修改语句没有from关键字。

7.3、删除操作

7.3.1、语法

DELETE FROM 表名 WHERE [条件]

7.3.2、练习

-- 删除 id 为 2 的学生信息
DELETE FROM t_student WHERE id=2;
-- 删除叶孤城的所有信息
DELETE FROM t_student WHERE name='叶孤城'

7.3.3、注意

  1. FROM 不能写成 FORM

  2. 如果省略了 WHERE 子句,则全表的数据都会被删除

八、DQL 查询操作

8.1、语法说明

SELECT1,列2,列3... FROM 表名 [WHERE];
-- SELECT 选择要查询的列
-- FROM 提供数据源 (表、视图或其他的数据源)
-- 可以写*表示查询所有列,但是在实际开发中基本上不会使用,性能低,实际开发中是将所有字段列出来

8.2、普通查询

8.2.1、设置别名

8.2.1.1、语法

SELECT 列名 AS 别名 FROM 表名 [WHERE];
SELECT 列名 别名 FROM 表名 [WHERE]

8.2.1.2、作用

  1. 改变列的标题头。
  2. 作为计算结果的含义。
  3. 作为列的别名。
  4. 如果别名中使用特殊字符,或是强制大小写或有空格时都需要加单引号。

8.2.1.3、例子

-- 查询所有货品的id,名称,各进50个,并且每个运费1元的成本(使用别名)
SELECT id,productName,(costPrice + 1) * 50 1 AS allPrice FROM product
SELECT id,productName,(costPrice + 1) * 50 allPrice FROM product

8.2.2、按照格式输出

    为方便用户浏览查询结果数据,有时需要设置查询结果的显示格式,可以使用 CONCAT 函数来 连接字符串。

8.2.2.1、语法

CONCAT(字符串1,字符串2,...)

8.2.2.2、实战

-- 查询商品的名字和零售价。格式: xxx 商品的零售价为:ooo
SELECT CONCAT(productName,'商品的零售价为:',salePrice) FROM product

8.2.3、消除重复的数据

    distinct前面不能接其他的字段,他只能出现在所有字段的最前方。他表示的意思是后面所有的字段联合起来一起去重。

SELECT DISTINCT 列名, ... FROM 表名;

8.2.4、算数运算符

    对 number 型数据可以使用算数操作符创建表达式     他有如下优先级:

  1. 乘法和除法的优先级高于加法和减法。
  2. 同级运算的顺序是从左到右。
  3. 表达式中使用"括号"可强行改变优先级的运算顺序
-- 查询所有货品的id,名称和批发价(批发价=卖价*折扣)
SELECT id,productName,salePrice * cutoff FROM product
-- 查询所有货品的id,名称,和各进50个的成本价(成本=costPirce)
SELECT id,productName,costPrice * 50 FROM product
-- 查询所有货品的id,名称,各进50个,并且每个运费1元的成本
SELECT id,productName,(costPrice + 1) * 50 FROM product

8.2.5、比较运算符

    比较运算符有如下几个:

  1. =
  2. >
  3. <
  4. <=
  5. != (<> 等价 !=)
-- 查询商品名为 罗技G9X 的货品信息
SELECT * FROM product WHERE productName='罗技G9X';
-- 查询零售价小于等于 200 的所有货品信息
SELECT * FROM product WHERE salePrice <= 200
-- 查询批发价大于 350 的货品信息
SELECT *,salePrice * cutoff allPrice FROM product WHERE salePrice * cutoff > 350

8.2.6、逻辑运算符

运算符含义
AND如果组合的条件都是TRUE,返回TRUE
OR如果组合的条件之一是TRUE,返回TRUE
NOT如果下面的条件是FALSE,返回 TRUE,如果是 TRUE ,返回 FALSE

8.2.7、范围匹配

    范围匹配:BETWEEN AND 运算符,一般使用在数字类型的范围上。但对于字符数据和日期类型同样可

用。需要两个数据。

8.2.7.1、语法

WHERE 列名 BETWEEN minValue AND maxValue; -- 闭区间

8.2.7.2、例子

-- 查询零售价在300-400 之间的货品信息
SELECT * FROM product WHERE salePrice BETWEEN 300 AND 400
-- 查询零售价不在300-400之间的货品信息
SELECT * FROM product WHERE NOT salePrice BETWEEN 300 AND 400

8.2.8、集合查询

    集合查询: 使用 IN 运算符,判断列的值是否在指定的集合中。

8.2.8.1、语法

WHERE 列名 IN (值1,值2....);

8.2.8.2、例子

-- 查询分类编号为2,4的所有货品的id,货品名称,
SELECT id,productName FROM product WHERE dir_id IN (2,4)
-- 查询分类编号不为2,4的所有货品的id,货品名称,
SELECT id,dir_id,productName FROM product WHERE dir_id NOT IN (2,4)

8.2.9、判空

    IS NULL: 判断列的值是否为空值,非空字符串,空字符串使用==判断。

8.2.9.1、语法

WHERE 列名 IS NULL;

8.2.9.2、例子

-- 查询商品名为NULL的所有商品信息。
SELECT * FROM product WHERE productName IS NULL;
SELECT * FROM product WHERE supplier =''

8.2.9.3、注意

    使用=来判断只能判断空字符串,不能判断null 的,而使用IS NULL只能判断null值,不能判断空

字符串。

8.2.10、过滤查询

    使用 WHERE 子句限定返回的记录

8.2.10.1、语法

SELECT <selectList>
FROM 表名
WHERE 条件;

8.2.10.2、注意

  1. WHERE子句在 FROM 子句后。

  2. 查询语句的字句的执行顺序 FROM 子句: 从哪张表中去查询数据 => WHERE 子句 : 筛选需要哪些行的数据 => SELECT 子句: 筛选要显示的列。

8.2.11、模糊查询

    模糊查询数据使用 LIKE 运算符执行通配查询,他有两个通配符:

  1. %:表示可能有零个或者任意多个字符。
  2. _:表示任意的一个字符。

8.2.11.1、语法

WHERE 列名 Like '%M_'

8.2.11.2、例子

-- 查询货品名称匹配'%罗技M9_' 的所有货品信息
SELECT * FROM product WHERE productName LIKE '%罗技M9_'

8.3、结果排序

    使用 ORDER BY 子句将查询结果进行排序,他有两种排序的模式:

  1. ASC : 升序(默认)。
  2. DESC:降序。

    ORDER BY 子句出现在,SELECT 语句的最后。

8.3.1、例子

--单列排序: 选择id,货品名称,分类编号,零售价并且按零售价降序排序
SELECT id,productName,dir_id,salePrice FROM product ORDER BY salePrice DESC
--多列排序: 选择id,货品名称,分类编号,零售价先按分类编号降序排序,再按零售价升序排序
SELECT * FROM product ORDER BY dir_id DESC,salePrice ASC

8.3.2、注意

  1. 谁在前面谁先排序。
  2. 如果列的别名使用 ' ' 则按此别名进行的排序无效。
-- 反例
SELECT id,salePrice 'sp' FROM product ORDER BY 'sp'

8.4、分页查询

    limit是mysql特有的,他用于取结果集中的部分数据,Oracle中有一个相同的机制,叫rownum。

    limit是SQL语句最后执行的环节。

8.4.1、语法

SELECT <selectList>
FROM 表名
[WHERE] LIMIT ?,?
-- 第一个? : 开始行的索引数 beginIndex,默认为0
-- 第二个? : 每页显示的最大记录数 pageSize
-- 每页显示 3条数据
-- 第一页: SELECT * FROM product LIMIT 0,3
-- 第三页: SELECT * FROM product LIMIT 6,3
-- 第八页: SELECT * FROM product LIMIT 21,3
-- 当前页 : currentPage
-- 每页显示的最大记录数: pageSize

8.4.2、通用的标准分页sql

    beginIndex = (currentPage - 1) * pageSize

8.4.3、案例

案例

    找出工资排名在4到6名的员工

select name,sal,from emp order by desc limit 3,6;

8.5、分组函数

  • COUNT(*) : 统计表中有多少条记录
  • SUM(列) : 汇总列的总和
  • MAX(列) : 获取某一列的最大值
  • MIN(列) : 获取某一列的最小值
  • AVG(列) : 获取列的平均值
-- 查询货品表中有多少数据
SELECT COUNT(*) FROM product
-- 计算所有货品的总的进货价
SELECT SUM(costPrice) FROM product

注意:

  1. 分组忽略null,无需额外过滤是否为null这个条件。**
  2. SQL语句中有一个语法规则,分组函数不可以直接使用在where字句当中。
  3. count(*)count(具体的字段的区别)
    • count(*)一定是总记录数,和字段无关。
    • count(具体的某个字段)是这个字段不为空的记录数。

8.6、分组查询

8.6.1、group by

group by:按照某个字段或者是某些字段进行分组。

    聚合函数分组会和group by一起联合使用,并且任何一个分组函数都是在group by语句执行结束之后才会执行。当一条sql语句没有group by的话,整张表的数据会自成一组。     SQL语句中有一个语法规则,分组函数不可以直接使用在where字句当中。原因是因为:group by是在where执行之后才会执行。如下面这条错误的sql语句:

select * from emp where sal > avg(sal);

    当执行到avg(sal)的时候,还没有执行group by,所以没办法执行分组函数。还没有分组就不可以执行分组函数。

需求:求每一个工作岗位的最高薪资

select max(sal),job from emp group by job;

    结论:当一条sql语句中有group by的时候,select 后面只允许出现分组函数或者是参加分组的字段。

需求:找出每个部门不同工作岗位的最高薪资)

select
	deptno ,job ,max(sql)
from 
	emp
group by
	deptno,job

8.6.2、having

    having:having是对分组之后的数据进行再次过滤。

需求:找出每个部门的平均薪资,要求显示薪资大于2000的数据

select val(sal),deptno from emp group by deptno having val(sal) > 2000;

8.6.3、group by和having的总结

    能用where过滤的就先用where过滤,无法用where过滤的在用having,但是having一定要搭配group by使用,先分组在过滤。

8.6、DQL字句的执行顺序

select 
	...
from 
	...
where
	...
group by
	...
having
	...
order by
	...
limit
	...
  1. from: 从哪张表中去查数据。
  2. where: 筛选需要的行数据。
  3. group by :分组
  4. having:对分组的数据进行再次过滤
  5. SELECT : 筛选需要显示的列的数据。
  6. ORDER BY : 排序操作。

九、多表查询

9.1、连接查询

    在实际开发中,大部分的情况下都不是从单表中查询数据,一般是多张表进行联合查询取出最终的结果,一般一个业务都会对应多张表。

​ 连接查询的分类有两种:

  1. SQL92(语法较老,过时)。
  2. SQL99(语法比较新)。

9.2、笛卡尔积现象

    当两张表进行连接查询的时候,没有任何条件进行限制,最终查询的结果条数是两张表记录条数的乘积,这个现象称为笛卡尔积现象。

    我们在开发的时候一般会给表起别名,他有两个好处:

  1. 执行效率高。
  2. 可读性好
select 
	e.ename,d.dname
from
	emp e,dept d

    这样出现的条数就是两张表条数的乘积。

    既然出现了笛卡尔积现象,我们就要避免笛卡尔积现象,避免笛卡尔积现象的措施就是增加条件进行过滤,但是避免了笛卡尔积你现象,会减少记录匹配的次数吗?答案是不会,次数还是两张表条数的乘积,只不过显示的是有效的记录数。

9.3、内连接

    假设A和B两张表进行连接,使用内连接的话,凡是A表和B表能够匹配上的记录都会被查询出来,AB两张表是平等的,没有主副之分,这就是内连接。

9.3.1、等值连接

    内连接最大的特点是:条件是等量关系。

select
	...
from
	...
inner join -- inner是可以省略的,带着inner可读性更好
	...
on 
	连接条件
where
	...

select 
	e.name,d.name 
from 
	emp e 
inner join -- inner是可以省略的,带着inner可读性更好
	dept d 
on 
	e.deptno =  d.deptno

    SQL99语法结构更清晰一些,表的连接条件和后来的where过滤条件分离了。

9.3.2、非等值连接

    连接条件中的关系是非等量关系。

select e.name,e.sal,e.grade
from emp e
join salgrade s
on e.sal between s.local and s.hisal

9.3.3、自连接

    最大的特点是一张表看成两张表,自己连接自己。(不常用)

9.4、外连接

    假设A表和B表进行连接,使用外连接的话,AB两张表有一张表是主表,一张表是副表,主要查询主表中的数据,捎带着查询副表。

    当副表中的数据没有和主表中的数据匹配上的时候副表自动模拟出NULL与之匹配。主表的数据会无条件的全部查询出来。

9.4.1、外连接的分类

​ 外连接分为两类:

  1. 左外连接(左连接 LEFT):表示左边的这张表是主表。
  2. 右外连接(右连接 RIGHT):表示右边的这张表是主表。

​ 左连接有连接的写法,右连接也有对应的左连接的写法。用左连接LEFT的时候,说明上面(左边)的表是主表。

9.4.1.1、左连接

SELECT * FROM emp e LEFT OUTER JOINdept d ON e.deptno=d.deptno;

注意:OUTER可以省略

    左连接是先查询出左表(即以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示NULL。

9.4.1.2、右连接

    右连接就是先把右表中所有记录都查询出来,然后左表满足条件的显示,不满足显示NULL。

需求:

    dept表中的40部门并不存在员工,但在右连接中,如果dept表为右表,那么还是会查出40部门,但相应的员工信息为NULL。

SELECT * FROM emp e RIGHT OUTER JOIN dept d ON e.deptno=d.deptno

9.4.2、注意

    内连接说明两张表是平等的,没有主副之分。

    外连接说明有一张表是主表,另一张表是副表。

    在开发中外连接居多,因为内连接查询的数据会丢失。

9.5、三张表连接

select ...
from
	...
join
	...
on
	...
join
	...
on
	...(条件)

9.6、union

    union关键字可以用于将查询结果集相加。他是连接两个查询结果的,可以用于两张不相干的表中的数据拼接在一起显示。

    注意:union必须用于两张列数相同的表进行查询,否则无法显示。

案例

    查询工作岗位是MANAGER和SALESMAN的员工

select ename,job from  emp where job = 'MANAGER'
union
select ename,job from  emp where job = 'SALESMAN'

十、子查询

10.1、子查询概述

    select语句中嵌套select语句,被嵌套的select语句就是子查询,他可以出现的位置有select、from、where后。

10.2、where子句中使用

案例

​     找出高于平均薪资的员工信息

select * 
from emp 
where sal > (select avg(sal) from emp);

10.3、from字句后使用

案例

    找出每个部门平均薪水的薪资等级。

  1. 先找出每个部门的平均薪水(按照部门编号分组,求sal的平均值)
select deptno,avg(sal) avgsal from emp group by deptno
  1. 将以上的查询结果作为临时表t,让t表和salgrade(薪水等级表) s连接,条件是:t.avgsal between s.losal and s.hisal
select 
	t.*,s.grade
from
	(select deptno,avg(sal) avgsal from emp group by deptno) t
join
	salgrade s
on
	t.avgsal between s.losal and s.hisal

10.4、在select后使用

需求

    找出每个员工所在的部门名称,要求显示员工名和部门名。

select 
	e.ename,
	(select d.dname from dept d where e.deptno = d.deptno) dname
from 
	emp e;

十一、事务

11.1、什么是事务

    一个事务是一个i完整的业务逻辑单元,不可再分。事务可以保证多个操作原子性,要么全成功,要么全失败。对于数据库来说事务保证批量的DML要么全成功,要么全失败。

​ 和事务相关的语句只有DML语句,因为他们这三个语句都是和数据库表中的数据相关的。事务的存在是为了保证数据的完整性、安全性。

11.2、开启事务的原理

    假设我们完成一个操作,需要先执行一条insert,然后再执行一条update,最后执行一条delete,在mysql中执行流程可以这么理解:

在这里插入图片描述

11.3、事务的特征

    事务具有四个特征ACID

  1. 原子性(Atomicity)

    事务是最小的工作单元,不可再分。整个事务中的所有操作,必须作为一个单元全部完成(取消)。

  1. 一致性(Consistency)

    事务必须保证多条DML语句同时成功或者同时失败。

  1. 隔离性(Isolation)

    一个事务不会影响其他事务的运行。

  1. 持久性(Durability)

    最终该事务对数据库所作的更改将持久地保存在硬盘文件之中,事务才算成功。

     MySQL事务默认情况下是自动提交的,可以通过命令来改成手工提交。

start transaction;

11.4、隔离性详解

11.4.1、并发访问可能导致的问题

####  11.4.1.1、脏读取

    一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交,这就出现了脏读取。

11.4.1.2、不可重复读

    在同一个事务中,同一个读操作对同一个数据的前后两次读取产生了不同的结果,这就是不可重复读。

11.4.1.3、幻读

    幻像读是指在同一个事务中以前没有的行,由于其他事务的提交而出现的新行。幻读强调的是前后读的行数不一样。

11.4.2、隔离级别

    InnoDB 实现了四个隔离级别,用以控制事务所做的修改,并将修改通告至其它并发的事务。隔离级别从低往高依次是:

  1. 读未提交(READ UMCOMMITTED)

  2. 读已提交(READ COMMITTED)

  3. 可重复读(REPEATABLE READ) MySQL默认

  4. 串行化(SERIALIZABLE)

在这里插入图片描述

11.4.2.1、读未提交

    对方的事务还没有提交,我们当前事务可以读取到对方未提交的数据。这种隔离级别是最低的,读为未提交存在脏读现象,表示堵到了脏数据。

11.4.2.2、读已提交

    对方事务提交之后的数据我们才可以读到,这种隔离级别解决了脏读现象,但是却出现了不可重复读现象。

    这个级别是oracle的默认隔离级别。

11.4.2.3、可重复读

    我们无法看到已提交的事务了,这种隔离级别虽然解决了不可重复读的问题,但是却带来了幻读的问题。比方说一个线程删除了数据库中的所有数据,但是我们依然读取的是原来的数据,读到的是数据库的备份。

MySQL的默认级别。

11.4.2.4、串行化

    将一个事务与其他事务完全地隔离。两个事务不可以并发,线程之间需要排队,也叫作序列化。虽然很安全,但是性能很低且客户的体验不好。

十二、索引

12.1、什么是索引

    索引相当于一本书的目录,通过目录可以快速找到对应的资源。索引被用来快速找出在一个列上用一特定值的行,索引可以有效地缩小扫描的范围。添加索引是给某个字段或者是某些字段添加的。

    在数据库方面,查询一张表的时候有两种检索方式:

  1. 全表扫描
  2. 根据索引检索(效率高)

    索引虽然可以提高检索的效率,但是不能随意添加索引,因为索引也是数据库中的对象,也需要数据库不断地维护,维护需要成本的。比如表中的的数据如果经常被修改的话就不适合添加索引,因为数据一旦被修改,索引需要重新排序。

12.2、什么时候需要创建索引

  1. 数据量庞大。
  2. 该字段很少的DML操作(因为字段进行修改操作,索引也需要维护)。
  3. 该字段经常出现在where子句中(经常根据哪个字段查询)

注意:主键和具有unique约束的字段会自动添加索引,根据主键查询的效率高,尽量根据主键索引,我们可以查询sql语句的执行计划。他的底层是B+Tree。

 explain select * from emp where SAL = 1500;
image-20210106171850865

    type字段的值时ALL表示是全表扫描(没有添加索引)。rows表示搜索了14条数据。

12.3、添加索引

-- 给emp表的sal字段添加一个索引,名称为emp_sal_index
create index emp_sal_index on emp(sal);

-- 语法格式
create index 索引名称 on 表名(字段名)

在这里插入图片描述

12.4、查看索引

-- 查看索引的语法
show index from emp;

-- 语法格式
show index from 表名;

在这里插入图片描述

12.5、删除索引

-- 删除索引的语法
drop index 索引名称 on 表名;

12.6、索引的原理

    索引底层采用的数据结构是B+Tree,通过B+Tress缩小扫描范围,底层索引进行排序、分区,索引会携带在表中的物理地址,最终通过索引检索到数据之后,获取到关联的物理地址,通过物理地址定位到表中的数据,效率是最高的(不走表,走硬盘)。

select ename from emp where ename = 'SMITH';

​ 通过索引sql语句会转换

select ename from emp where 物理地址 = '索引检索到的物理地址'

12.7、索引的分类

  1. 单一索引:给打那个字段添加索引。
  2. 复合索引:给多个字段联合起来添加索引。
  3. 主键索引:主键上会自动添加索引。
  4. 唯一索引:有unique约束的字段上会自动添加索引。

12.8、索引的失效

    在模糊查询的时候,如果第一个通配符使用的是%,这个索引会失效,因为他不知道一开始匹配的字符是什么。

十三、视图

13.1、什么是视图

    视图是一种根据查询(也就是SELECT表达式)定义的数据库对象,用于获取想要看到和使用的局部数据。所以他也称为虚拟表。

    视图是站在不同的角度看到数据,同一张表的数据,通过不同的角度去看待数据。

    我们可以对视图进行增删改查,会影响到原表的数据,通过视图来影响原表数据的,并不是直接操作原表。只有DQL语句才可以以视图对象的方式创建出来。

在这里插入图片描述

13.2、创建视图

-- 语法格式
create view 视图名 as select语句

-- 示范
create view myview as select empo,ename from emp;

13.3、修改视图

-- 语法格式
update 视图名 set 列名 = '值' where 条件;

13.4、删除视图

-- 语法格式
delete from 视图名 where 条件;

-- 示范
delete from myview where empo = '12134';

13.5、视图的作用

    视图可以隐藏表的实现细节,保密级别比较高的系统,数据库只对外提供相关的视图,面向视图对象进行CRUD。

十四、数据库设计三范式

    设计范式是设计表的依据,按照这三个范式设计的表不会出现数据冗余。但是在实际开发中,根据客户的需求,可能会拿数据冗余来换取执行速度,拿空间换时间。

14.1、第一范式

    任何一张表都应该有主键,且每一个字段原子性不可再分。

14.2、第二范式

    建立在第一范式的基础上,所有非主键字段完全依赖于主键,不能产生部分依赖。

​ 典型的例子就是解决多对多的问题上,遇到多对多的时候,背口诀:多对多?三张表,关系表两外键

14.3、第三范式

    建立在第二范式的基础上,所有非主键字段直接依赖主键,不能产生传递依赖。

    典型的例子就是一对多,遇到一对多问题的时候背口诀:一对多?两张表,多的表加外键。

14.4、一对一关系的设计方案

14.4.1、主键共享

​ t_user_login 用户登录表

id(pk)usernamepassword
1zs123
2ls456

t_user_detail 用户详细信息表

id(pk+fk)realnametel
1张三111
2李四456

14.4.2、外键唯一

t_user_login 用户登录表

id(pk)usernamepassword
1zs123
2ls456

t_user_detail 用户详细信息表

id(pk)realnameteluserid(fk+unique)
1张三1112
2李四4562

视图

-- 语法格式
delete from 视图名 where 条件;

-- 示范
delete from myview where empo = '12134';

13.5、视图的作用

    视图可以隐藏表的实现细节,保密级别比较高的系统,数据库只对外提供相关的视图,面向视图对象进行CRUD。

十四、数据库设计三范式

    设计范式是设计表的依据,按照这三个范式设计的表不会出现数据冗余。但是在实际开发中,根据客户的需求,可能会拿数据冗余来换取执行速度,拿空间换时间。

14.1、第一范式

    任何一张表都应该有主键,且每一个字段原子性不可再分。

14.2、第二范式

    建立在第一范式的基础上,所有非主键字段完全依赖于主键,不能产生部分依赖。

    典型的例子就是解决多对多的问题上,遇到多对多的时候,背口诀:多对多?三张表,关系表两外键

14.3、第三范式

    建立在第二范式的基础上,所有非主键字段直接依赖主键,不能产生传递依赖。

    典型的例子就是一对多,遇到一对多问题的时候背口诀:一对多?两张表,多的表加外键。

14.4、一对一关系的设计方案

14.4.1、主键共享

​ t_user_login 用户登录表

id(pk)usernamepassword
1zs123
2ls456

t_user_detail 用户详细信息表

id(pk+fk)realnametel
1张三111
2李四456

14.4.2、外键唯一

t_user_login 用户登录表

id(pk)usernamepassword
1zs123
2ls456

t_user_detail 用户详细信息表

id(pk)realnameteluserid(fk+unique)
1张三1112
2李四4562