Mysql入门

视频地址:B站宋红康数据库教程

一、数据库概述

1.1 为什么使用数据库

持久化保存数据。

Mysql入门_第1张图片

1.2 数据库与数据库管理系统

  • DB:数据库(Database)。即存储数据的“仓库”,其本质是一个文件系统。它保存了一系列有组织的数据。
  • DBMS:数据库管理系统(Database Management System)。是一种操纵和管理数据库的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制。用户通过数据库管理系统访问数据库中表内的数据。
  • SQL:结构化查询语言(Structured Query Language)。专门用来与数据库通信的语言。

1.3 Mysql介绍

  • MySQL是一个开放源代码的关系型数据库管理系统 ,由瑞典MySQL AB(创始人Michael Widenius)公司1995年开发,迅速成为开源数据库的 No.1
  • MySQL是一种关联数据库管理系统,将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
  • MySQL是开源的,不需要支付额外的费用。
  • MySQL是可以定制的,采用了 GPL(GNU General Public License) 协议,可以修改源码来开发自己的MySQL系统。
  • MySQL支持大型的数据库。可以处理拥有上千万条记录的大型数据库。MySQL支持大型数据库,支持5000万条记录的数据仓库,32位系统表文件最大可支持 4GB ,64位系统支持最大的表文件为 8TB 。
  • MySQL使用 标准的SQL数据语言 形式。
  • MySQL可以允许运行于多个系统上,并且支持多种语言。这些编程语言包括C、C++、Python、Java、Perl、PHP和Ruby等。

1.4 关系型数据库设计规则

1.4.1 表、记录、字段

E-R(entity-relationship,实体-联系)模型中有三个主要概念是: 实体集 、 属性 、 联系集 。

  • 一个实体集(class)对应于数据库中的一个表(table),一个实体(instance)则对应于数据库表中的一行(row),也称为一条记录(record)。
  • 一个属性(attribute)对应于数据库表中的一列(column),也称为一个字段(field)。
  • 联系集指定的是各种实体以及实体之间的各种联系。

1.4.2 表的关联关系

  • 一对一关联
  • 一对多关联
  • 多对多关联
  • 自我引用

二、Mysql数据库搭建(windows环境)

2.1 卸载

1、停止Mysql服务

Mysql入门_第2张图片 

2、软件卸载

Mysql入门_第3张图片

 3、残余文件清理

通过everything等工具搜索mysql残余文件,进行删除。

4、清理注册表

HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\MySQL服务 目录删除
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\Eventlog\Application\MySQL服务 目录删除
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\MySQL服务 目录删除
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MySQL服务目录删除
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MySQL服务删除

5、删除环境变量

Mysql入门_第4张图片

2.2 下载安装配置

1、官网下载msi安装包:MySQL

Mysql入门_第5张图片

 2、进行安装

Mysql入门_第6张图片

Mysql入门_第7张图片

Mysql入门_第8张图片

Mysql入门_第9张图片

Mysql入门_第10张图片

Mysql入门_第11张图片

Mysql入门_第12张图片

Mysql入门_第13张图片

2.3 登录

首先需要先保证服务已正常启动。

检查如下项:

  • 安装目录数据正常
  • data目录数据正常
  • 服务正常启动
  • 已配置环境变量

2.3.1 登录

# 格式 
mysql -h 主机名 -P 端口号 -u 用户名 -p密码 # 举例 mysql -hlocalhost -P3306 -uroot -pabc123 mysql -uroot -p

2.3.2 登出

exit 
或 
quit

2.3.3 演示

Mysql入门_第14张图片

2.3.4 Mysql5.7默认编码设置

5.7版本中,默认创建的库和表采用latin编码,不支持中文。需要更改默认编码。

修改mysql的数据目录下的my.ini配置文件:

default-character-set=utf8 #默认字符集

[mysqld] # 大概在76行左右,在其下添加...
character-set-server=utf8
collation-server=utf8_general_ci

2.4 图形化管理工具

图形化工具提供更方便的管理交互,常用的工具有:

  • Navicat
  • DBeaver
  • DataGrip

2.5 目录结构

主要目录与文件

  • bin:所有MySQL的可执行文件。如:mysql.exe
  • data:系统数据库所在的目录
  • my.ini文件:MySQL的主要配置文件

三、基本SELECT语句

3.1 SQL概述

SQL(Structured Query Language,结构化查询语言)是使用关系模型的数据库应用语言, 与数据直接打交道。

后由美国国家标准局(ANSI)开始着手制定SQL标准,先后有 SQL-86 , SQL-89 , SQL-92 , SQL-99 等标准。

SQL 有两个重要的标准,分别是 SQL92 和 SQL99,它们分别代表了 92 年和 99 年颁布的 SQL 标准,我们今天使用的 SQL 语言依然遵循这些标准。

不同的数据库生产厂商都支持SQL语句,但都有特有内容。

sql分类:

  • DDL(Data Definition Languages、数据定义语言),这些语句定义了不同的数据库、表、视图、索引等数据库对象,还可以用来创建、删除、修改数据库和数据表的结构。主要的语句关键字包括 CREATE 、 DROP 、 ALTER 等。
  • DML(Data Manipulation Language、数据操作语言),用于添加、删除、更新和查询数据库记录,并检查数据完整性。主要的语句关键字包括 INSERT 、 DELETE 、 UPDATE 、 SELECT 等。SELECT是SQL语言的基础,最为重要。
  • DCL(Data Control Language、数据控制语言),用于定义数据库、表、字段、用户的访问权限和安全级别。主要的语句关键字包括 GRANT 、 REVOKE 、 COMMIT 、 ROLLBACK 、 SAVEPOINT 等。

3.2 SQL语言规范与规则

3.2.1 通用规则

  • SQL 可以写在一行或者多行。为了提高可读性,各子句分行写,必要时使用缩进
  • 每条命令以 ; 或 \g 或 \G 结束
  • 关键字不能被缩写也不能分行
  • 关于标点符号
    • 必须保证所有的()、单引号、双引号是成对结束的
    • 必须使用英文状态下的半角输入方式
    • 字符串型和日期时间类型的数据可以使用单引号(' ')
    • 表示列的别名,尽量使用双引号(" "),而且不建议省略as

3.2.2 SQL大小写规范 (建议遵守)

  • MySQL 在 Windows 环境下是大小写不敏感的
  • MySQL 在 Linux 环境下是大小写敏感的
    • 数据库名、表名、表的别名、变量名是严格区分大小写的
    • 关键字、函数名、列名(或字段名)、列的别名(字段的别名) 是忽略大小写的。
  • 推荐采用统一的书写规范:
    • 数据库名、表名、表别名、字段名、字段别名等都小写SQL
    • 关键字、函数名、绑定变量等都大写

3.2.3 注释

可以使用如下格式的注释结构

单行注释:#注释文字(MySQL特有的方式)
单行注释:-- 注释文字(--后面必须包含一个空格。)
多行注释:/* 注释文字 */

3.2.4 命名规则(暂时了解)

  • 数据库、表名不得超过30个字符
  • 变量名限制为29个必须只能包含 A–Z, a–z, 0–9, _共63个字符
  • 数据库名、表名、字段名等对象名中间不要包含空格
  • 同一个MySQL软件中,数据库不能同名;同一个库中,表不能重名;同一个表中,字段不能重名
  • 保证字段没有和保留字、数据库系统或常用方法冲突。如果坚持使用,请在SQL语句中使用``(着重号)引起来
  • 保持字段名和类型的一致性,在命名字段并为其指定数据类型的时候一定要保证一致性。假如数据类型在一个表里是整数,那在另一个表里别变成字符型了

3.2.5 数据导入指令

在命令行客户端登录mysql,使用source指令导入

mysql> source d:\mysqldb.sql

3.3 基本SELECT语句

3.3.1 SELECT

SELECT 1; #没有任何子句 
SELECT 9/2; #没有任何子句

3.3.2 SELECT...FROM

SELECT 标识选择哪些列 FROM 标识从哪个表中选择

3.3.3 列的别名

SELECT last_name AS name, commission_pct comm FROM employees;

3.3.4 空值参与运算

所有运算符或列值遇到null值,运算的结果都为null。

3.3.5 着重号

我们需要保证表中的字段、表名等没有和保留字、数据库系统或常用方法冲突。

如果真的相同,请在SQL语句中使用一对``(着重号)引起来。

SELECT * FROM `order`;

3.3.6 查询常数

SELECT 查询还可以对常数进行查询,就是在 SELECT 查询结果中增加一列固定的常数列。

SELECT 'XIANG' as corporation, last_name FROM employees;

3.4 显示表结构

使用DESCRIBE 或 DESC 命令,表示表结构。

DESCRIBE employees; 
DESC employees;

3.5 过滤数据

  • 使用WHERE 子句,将不满足条件的行过滤掉
  • WHERE子句紧随 FROM子句
SELECT 字段1,字段2 FROM 表名 WHERE 过滤条件

四、运算符

4.1 算术运算符

算术运算符主要用于数学运算,其可以连接运算符前后的两个数值或表达式,对数值或表达式进行加(+)、减(-)、乘(*)、除(/)和取模(%)运算。

Mysql入门_第15张图片

4.2 比较运算符

比较运算符用来对表达式左边的操作数和右边的操作数进行比较,比较的结果为真则返回1,比较的结果为假则返回0,其他情况则返回NULL。

比较运算符经常被用来作为SELECT查询语句的条件来使用,返回符合条件的结果记录。

Mysql入门_第16张图片

null相关判断

  • IS NULL
  • null
  • IS NOT NULL

4.3 逻辑运算符

逻辑运算符主要用来判断表达式的真假,在MySQL中,逻辑运算符的返回结果为1、0或者NULL。

Mysql入门_第17张图片

4.4 位运算符

位运算符是在二进制数上进行计算的运算符。位运算符会先将操作数变成二进制数,然后进行位运算,最后将计算结果从二进制变回十进制数。

Mysql入门_第18张图片

4.5 运算符的优先级

Mysql入门_第19张图片

4.6 使用正则表达式查询

MySQL中使用REGEXP关键字指定正则表达式的字符匹配模式。

Mysql入门_第20张图片

举例:

-- 查询f_name字段以字母‘b’开头的记录
SELECT * FROM fruits WHERE f_name REGEXP '^b';

-- 查询f_name字段以字母‘y’结尾的记录
SELECT * FROM fruits WHERE f_name REGEXP 'y$';

-- 查询f_name字段值包含字母‘a’与‘g’且两个字母之间只有一个字母的记录
SELECT * FROM fruits WHERE f_name REGEXP 'a.g';

五、排序和分页

5.1 排序数据

  • 使用 ORDER BY 子句排序
    • ASC(ascend): 升序
    • DESC(descend):降序
  • ORDER BY 子句在SELECT语句的结尾
SELECT last_name, department_id, salary FROM employees ORDER BY department_id, salary DESC;

5.2 分页

MySQL中使用 LIMIT 实现分页

LIMIT [位置偏移量,] 行数

位置偏移量从0开始。

示例:

select * from employees limit 0,10

MySQL 8.0可以使用新写法:

-- 等同于 LIMIT 0,10 
LIMIT 10 OFFSET 0

六、多表查询

多表查询,也称为关联查询,指两个或更多个表一起完成查询操作。

6.1 多表查询分类

6.1.1 等值连接和非等值连接

  • 等值连接:A表和B表通过相同的值作为连接条件
SELECT table1.column, table2.column 
FROM table1, table2 
WHERE table1.column1 = table2.column2; #连接条件
  • 非等值连接:通过范围条件作为连接条件
SELECT 
e.salary from employees e, job_grade j 
WHERE e.salary BETWEEN j.lowest_sal AND j.highest_sal;

6.1.2 自连接和非自连接

自连接:当table1和table2本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。然后两个表再进行内连接,外连接等查询。

6.1.3 内连接和外连接

内连接:合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行

外连接:两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。

SQL92:使用(+)创建连接

  • 在 SQL92 中采用(+)代表从表所在的位置。即左或右外连接中,(+) 表示哪个是从表。
  • Oracle 对 SQL92 支持较好,而 MySQL 则不支持 SQL92 的外连接。
  • 且在 SQL92 中,只有左外连接和右外连接,没有满(或全)外连接。
#左外连接
SELECT last_name,department_name
FROM employees ,departments
WHERE employees.department_id = departments.department_id(+);

#右外连接
SELECT last_name,department_name
FROM employees ,departments
WHERE employees.department_id(+) = departments.department_id;

SQL99使用JOIN...ON子句创建连接:

  • 可以使用 ON 子句指定额外的连接条件。
  • 这个连接条件是与其它条件分开的。
  • ON 子句使语句具有更高的易读性。
  • 关键字 JOIN、INNER JOIN、CROSS JOIN 的含义是一样的,都表示内连接
SELECT table1.column, table2.column,table3.column
FROM table1
JOIN table2 ON table1 和 table2 的连接条件
JOIN table3 ON table2 和 table3 的连接条件

6.2 UNION使用

合并查询结果 利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。

合并时,两个表对应的列数和数据类型必须相同,并且相互对应。

各个SELECT语句之间使用UNION或UNIONALL关键字分隔。

SELECT column,... FROM table1
UNION [ALL]
SELECT column,... FROM table2

UNION 操作符返回两个查询的结果集的并集,去除重复记录。

UNION ALL操作符返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重。

6.3 七种SQL JOIN的实现

Mysql入门_第21张图片

代码实现

#中图:内连接 A∩B
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`;

#左上图:左外连接
SELECT employee_id,last_name,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`;

#右上图:右外连接
SELECT employee_id,last_name,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`;


#左中图:A - A∩B
SELECT employee_id,last_name,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` IS NULL
 
#右中图:B-A∩B
SELECT employee_id,last_name,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE e.`department_id` IS NULL

SELECT employee_id,last_name,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` IS NULL
UNION ALL #没有去重操作,效率高
SELECT employee_id,last_name,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`;

#右下图
#左中图 + 右中图 A ∪B- A∩B 或者 (A - A∩B) ∪ (B - A∩B)
SELECT employee_id,last_name,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` IS NULL
UNION ALL
SELECT employee_id,last_name,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE e.`department_id` IS NULL

6.4 SQL99新特性

自然连接

NATURAL JOIN 用来表示自然连接。我们可以把自然连接理解为 SQL92 中的等值连接。它会帮你自动查询两张连接表中所有相同的字段 ,然后进行等值连接 。

SELECT employee_id,last_name,department_name FROM employees e NATURAL JOIN departments d;

USING连接

当我们进行连接的时候,SQL99还支持使用 USING 指定数据表里的同名字段进行等值连接。但是只能配合JOIN一起使用。比如:

SELECT employee_id,last_name,department_name FROM employees e JOIN departments d USING (department_id)

七、单行函数

函数在计算机语言的使用中贯穿始终,函数的作用是什么呢?它可以把我们经常使用的代码封装起来,需要的时候直接调用即可。

单行函数:

  • 操作数据对象
  • 接受参数返回一个结果
  • 只对一行进行变换
  • 每行返回一个结果
  • 可以嵌套
  • 参数可以是一列或一个值

7.1 数值函数

  • ABS(x) 返回x的绝对值
  • SIGN(X) 返回X的符号。正数返回1,负数返回-1,0返回0
  • PI() 返回圆周率的值
  • CEIL(x),CEILING(x) 返回大于或等于某个值的最小整数
  • FLOOR(x) 返回小于或等于某个值的最大整数
  • LEAST(e1,e2,e3…) 返回列表中的最小值
  • GREATEST(e1,e2,e3…) 返回列表中的最大值
  • MOD(x,y) 返回X除以Y后的余数
  • RAND() 返回0~1的随机值
  • RAND(x) 返回0~1的随机值,其中x的值用作种子值,相同的X值会产生相同的随机数
  • ROUND(x) 返回一个对x的值进行四舍五入后,最接近于X的整数
  • ROUND(x,y) 返回一个对x的值进行四舍五入后最接近X的值,并保留到小数点后面Y位
  • TRUNCATE(x,y) 返回数字x截断为y位小数的结果
  • SQRT(x) 返回x的平方根。当X的值为负数时,返回NULL
  • CONV(value,from,to) 将value的值进行不同进制之间的转换
  • ...

7.2 字符串函数

  • ASCII(S) 返回字符串S中的第一个字符的ASCII码值
  • CHAR_LENGTH(s) 返回字符串s的字符数。作用与CHARACTER_LENGTH(s)相同
  • LENGTH(s) 返回字符串s的字节数,和字符集有关
  • CONCAT(s1,s2,......,sn) 连接s1,s2,......,sn为一个字符串
  • CONCAT_WS(x,s1,s2,......,sn) 同CONCAT(s1,s2,...)函数,但是每个字符串之间要加上x
  • INSERT(str, idx, len,replacestr) 将字符串str从第idx位置开始,len个字符长的子串替换为字符串replacestr
  • REPLACE(str, a, b) 用字符串b替换字符串str中所有出现的字符串a
  • UPPER(s) 或 UCASE(s) 将字符串s的所有字母转成大写字母
  • LOWER(s) 或LCASE(s) 将字符串s的所有字母转成小写字母
  • LEFT(str,n) 返回字符串str最左边的n个字符
  • RIGHT(str,n) 返回字符串str最右边的n个字符
  • LPAD(str, len, pad) 用字符串pad对str最左边进行填充,直到str的长度为len个字符
  • RPAD(str ,len, pad) 用字符串pad对str最右边进行填充,直到str的长度为len个字符
  • LTRIM(s) 去掉字符串s左侧的空格
  • RTRIM(s) 去掉字符串s右侧的空格
  • TRIM(s) 去掉字符串s开始与结尾的空格
  • TRIM(s1 FROM s) 去掉字符串s开始与结尾的s1
  • TRIM(LEADING s1 FROM s) 去掉字符串s开始处的s1
  • TRIM(TRAILING s1 FROM s) 去掉字符串s结尾处的s1
  • REPEAT(str, n) 返回str重复n次的结果
  • SPACE(n) 返回n个空格
  • STRCMP(s1,s2) 比较字符串s1,s2的ASCII码值的大小
  • SUBSTR(s,index,len) 返回从字符串s的index位置其len个字符,作用与SUBSTRING(s,n,len)、MID(s,n,len)相同
  • LOCATE(substr,str) 返回字符串substr在字符串str中首次出现的位置,作用于POSITION(substr IN str)、INSTR(str,substr)相同。未找到,返回0
  • ELT(m,s1,s2,…,sn) 返回指定位置的字符串,如果m=1,则返回s1,如果m=2,则返回s2,如果m=n,则返回sn
  • FIELD(s,s1,s2,…,sn) 返回字符串s在字符串列表中第一次出现的位置

7.3 日期和时间函数

7.3.1 获取日期、时间

CURDATE() ,CURRENT_DATE() 返回当前日期,只包含年、月、日

CURTIME() , CURRENT_TIME() 返回当前时间,只包含时、分、秒

NOW() / SYSDATE() / CURRENT_TIMESTAMP() / LOCALTIME() /LOCALTIMESTAMP() 返回当前系统日期和时间

UTC_DATE() 返回UTC(世界标准时间)日期

UTC_TIME() 返回UTC(世界标准时间)时间

7.3.2 日期和时间戳转换

UNIX_TIMESTAMP() 以UNIX时间戳的形式返回当前时间。

SELECT UNIX_TIMESTAMP() 
->1634348884

UNIX_TIMESTAMP(date) 将时间date以UNIX时间戳的形式返回。

FROM_UNIXTIME(timestamp) 将UNIX时间戳的时间转换为普通格式的时间

7.3.3 获取月份、星期、星期数、天数

YEAR(date) / MONTH(date) / DAY(date) 返回具体的日期值

HOUR(time) / MINUTE(time) /SECOND(time) 返回具体的时间值

MONTHNAME(date) 返回月份:January,...

DAYNAME(date) 返回星期几:MONDAY,TUESDAY.....SUNDAY

WEEKDAY(date) 返回周几,注意,周1是0,周2是1,。。。周日是6

QUARTER(date) 返回日期对应的季度,范围为1~4

WEEK(date) , WEEKOFYEAR(date) 返回一年中的第几周

DAYOFYEAR(date) 返回日期是一年中的第几天

DAYOFMONTH(date) 返回日期位于所在月份的第几天

DAYOFWEEK(date) 返回周几,注意:周日是1,周一是2,。。。周六是7

7.3.4 日期操作函数

EXTRACT(type FROM date) 返回指定日期中特定的部分,type指定返回的值

Mysql入门_第22张图片

7.3.5 时间和秒数转换的函数

TIME_TO_SEC(time) 将 time 转化为秒并返回结果值。转化的公式为: 小时*3600+分钟*60+秒

SEC_TO_TIME(seconds) 将 seconds 描述转化为包含小时、分钟和秒的时间

7.3.6 计算日期和时间的函数

DATE_ADD(datetime, INTERVAL expr type)

ADDDATE(date,INTERVAL expr type) 返回与给定日期时间相差INTERVAL时间段的日期时间

DATE_SUB(date,INTERVAL expr type),

SUBDATE(date,INTERVAL expr type) 返回与date相差INTERVAL时间间隔的日期

Mysql入门_第23张图片

ADDTIME(time1,time2) 返回time1加上time2的时间。当time2为一个数字时,代表的是秒 ,可以为负数

SUBTIME(time1,time2) 返回time1减去time2后的时间。当time2为一个数字时,代表的是 秒 ,可以为负数

DATEDIFF(date1,date2) 返回date1 - date2的日期间隔天数

TIMEDIFF(time1, time2) 返回time1 - time2的时间间隔

FROM_DAYS(N) 返回从0000年1月1日起,N天以后的日期

TO_DAYS(date) 返回日期date距离0000年1月1日的天数

LAST_DAY(date) 返回date所在月份的最后一天的日期

MAKEDATE(year,n) 针 对给定年份与所在年份中的天数返回一个日期

MAKETIME(hour,minute,second) 将给定的小时、分钟和秒组合成时间并返回

PERIOD_ADD(time,n)

返回time加上n后的时间

7.3.7 日期格式化和解析

DATE_FORMAT(date,fmt) 按照字符串fmt格式化日期date值

TIME_FORMAT(time,fmt) 按照字符串fmt格式化时间time值

GET_FORMAT(date_type,format_type) 返回日期字符串的显示格式

STR_TO_DATE(str, fmt) 按照字符串fmt对str进行解析,解析为一个日期

Mysql入门_第24张图片

7.4 流程控制函数

IF(value,value1,value2) 如果value的值为TRUE,返回value1,否则返回value2

IFNULL(value1, value2) 如果value1不为NULL,返回value1,否则返回value2

CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2.... [ELSE resultn] END 相当于Java的if...else if...else...

CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN值1 .... [ELSE 值n] END 相当于Java的switch...case...

SELECT IF(1 > 0,'正确','错误')
->正确

SELECT IFNULL(null,'Hello Word')
->Hello Word

SELECT CASE
    WHEN 1 > 0 THEN '1 > 0'
    WHEN 2 > 0 THEN '2 > 0'
    ELSE '3 > 0' END
->1 > 0

7.5 加密和解密函数

PASSWORD(str) 返回字符串str的加密版本,41位长的字符串。加密结果 不可逆 ,常用于用户的密码加密

MD5(str) 返回字符串str的md5加密后的值,也是一种加密方式。若参数为NULL,则会返回NULL

SHA(str) 从原明文密码str计算并返回加密后的密码字符串,当参数为NULL时,返回NULL。 SHA加密算法比MD5更加安全 。

ENCODE(value,password_seed) 返回使用password_seed作为加密密码加密value

DECODE(value,password_seed) 返回使用password_seed作为加密密码解密value

7.6 Mysql信息函数

VERSION() 返回当前MySQL的版本号

CONNECTION_ID() 返回当前MySQL服务器的连接数

DATABASE(),SCHEMA() 返回MySQL命令行当前所在的数据库

USER(),CURRENT_USER()、SYSTEM_USER(),SESSION_USER() 返回当前连接MySQL的用户名,返回结果格式为“主机名@用户名”

CHARSET(value) 返回字符串value自变量的字符集

COLLATION(value) 返回字符串value的比较规则

八、聚合函数

聚合(或聚集、分组)函数,它是对一组数据进行汇总的函数,输入的是一组数据的集合,输出的是单个值。

聚合函数作用于一组数据,并对一组数据返回一个值。

聚合函数类型

  • AVG()
  • SUM()
  • MAX()
  • MIN()
  • COUNT()

问题:用count(*),count(1),count(列名)谁好呢?

其实,对于MyISAM引擎的表是没有区别的。这种引擎内部有一计数器在维护着行数。

Innodb引擎的表用count(*),count(1)直接读行数,复杂度是O(n),因为innodb真的要去数一遍。但好于具体的count(列名)。

问题:能不能使用count(列名)替换count(*)?

不要使用 count(列名)来替代 count(*) , count(*) 是 SQL92 定义的标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。

说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。

8.1 GROUP BY

可以使用GROUP BY子句将表中的数据分成若干组

SELECT column, group_function(column) FROM table [WHERE condition] [GROUP BY group_by_exp]

8.2 HAVING

过滤分组:HAVING子句

  1. 行已经被分组。
  2. 使用了聚合函数。
  3. 满足HAVING 子句中条件的分组将被显示。
  4. HAVING 不能单独使用,必须要跟 GROUP BY 一起使用。

8.3 SELECT执行过程

#方式1:
SELECT ...,....,...
FROM ...,...,....
WHERE 多表的连接条件
AND 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...
 
#方式2:
SELECT ...,....,...
FROM ... JOIN ...
ON 多表的连接条件
JOIN ...
ON ...
WHERE 不包含组函数的过滤条件
AND/OR 不包含组函数的过滤条件
GROUP BY ...,...
HAVING 包含组函数的过滤条件
ORDER BY ... ASC/DESC
LIMIT ...,...

 
#其中:
#(1)from:从哪些表中筛选
#(2)on:关联多表查询时,去除笛卡尔积
#(3)where:从表中筛选的条件
#(4)group by:分组依据
#(5)having:在统计结果中再次筛选
#(6)order by:排序
#(7)limit:分页

九、子查询

子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从MySQL 4.1开始引入。

9.1 单行子查询

Mysql入门_第25张图片

9.2 多行子查询

Mysql入门_第26张图片

举例:查询平均工资最低的部门id

#方式1:
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) = (
    SELECT MIN(avg_sal)
    FROM (
        SELECT AVG(salary) avg_sal
        FROM employees
        GROUP BY department_id
    ) dept_avg_sal
)


#方式2:
SELECT department_id
FROM employees
GROUP BY department_id
HAVING AVG(salary) <= ALL (
    SELECT AVG(salary) avg_sal
    FROM employees
    GROUP BY department_id
)

9.3 3 EXISTS 与 NOT EXISTS关键字

  • 关联子查询通常也会和 EXISTS操作符一起来使用,用来检查在子查询中是否存在满足条件的行。
  • 如果在子查询中不存在满足条件的行:
    • 条件返回 FALSE
    • 继续在子查询中查找
  • 如果在子查询中存在满足条件的行:
    • 不在子查询中继续查找
    • 条件返回 TRUE
  • NOT EXISTS关键字表示如果不存在某种条件,则返回TRUE,否则返回FALSE。

题目:查询公司管理者的employee_id,last_name,job_id,department_id信息

#方式一
SELECT employee_id, last_name, job_id, department_id
FROM employees e1
WHERE EXISTS ( SELECT *
    FROM employees e2
    WHERE e2.manager_id =
 e1.employee_id);

#方式二
SELECT DISTINCT e1.employee_id, e1.last_name, e1.job_id, e1.department_id
FROM employees e1 JOIN employees e2
WHERE e1.employee_id = e2.manager_id;

十、创建和管理表

10.1 基础知识

10.1.1 数据存储前置过程 

Mysql入门_第27张图片

MySQL 数据库系统从大到小依次是

  1. 数据库服务器
  2. 数据库
  3. 数据表
  4. 数据表的行与列 。

10.1.2 标志符命名规则

  • 数据库名、表名不得超过30个字符,变量名限制为29个
  • 必须只能包含 A–Z, a–z, 0–9, _共63个字符
  • 数据库名、表名、字段名等对象名中间不要包含空格
  • 同一个MySQL软件中,数据库不能同名;同一个库中,表不能重名;同一个表中,字段不能重名
  • 保证字段没有和保留字、数据库系统或常用方法冲突。如果坚持使用,请在SQL语句中使用`(着重号)引起来
  • 保持字段名和类型的一致性:在命名字段并为其指定数据类型的时候一定要保证一致性,假如数据类型在一个表里是整数,那在另一个表里可就别变成字符型了

10.1.3 数据类型

Mysql入门_第28张图片

10.2 管理数据库

创建数据库

CREATE DATABASE 数据库名;
CREATE DATABASE 数据库名 CHARACTER SET 字符集;
CREATE DATABASE IF NOT EXISTS 数据库名;

使用数据库

SHOW DATABASES; #有一个S,代表多个数据库
SELECT DATABASE(); #使用的一个 mysql 中的全局函数
SHOW TABLES FROM 数据库名; #查看指定库下所有的表
SHOW CREATE DATABASE 数据库名;# 查看数据库的创建信息

#使用/切换数据库
USE 数据库名;

修改数据库

#更改数据库字符集
ALTER DATABASE 数据库名 CHARACTER SET 字符集; #比如:gbk、utf8等

删除数据库

DROP DATABASE 数据库名;
DROP DATABASE IF EXISTS 数据库名;

10.3 创建表

新建表

CREATE TABLE [IF NOT EXISTS] 表名(
字段1, 数据类型 [约束条件] [默认值],
字段2, 数据类型 [约束条件] [默认值],
字段3, 数据类型 [约束条件] [默认值],
……
[表约束条件]
);

从已有表中复制

CREATE TABLE dept80
AS
SELECT employee_id, last_name, salary*12 ANNSAL, hire_date
FROM employees
WHERE department_id = 80;

10.4 修改表

# 追加列
ALTER TABLE 表名 ADD 【COLUMN】 字段名 字段类型 【FIRST|AFTER 字段名】;

# 删除列
ALTER TABLE 表名 DROP 【COLUMN】字段名

# 修改列
ALTER TABLE 表名 MODIFY 【COLUMN】 列名 数据类型 【DEFAULT 默认值】【FIRST|AFTER 字段名2】;
ALTER TABLE 表名 CHANGE 【COLUMN】 列名 新列名 新数据类型;

10.5 重命名表

RENAME TABLE 表名 TO 新表名;
ALTER table 表名 RENAME [TO] 新表名; 

10.6 删除表

DROP TABLE [IF EXISTS] 数据表1 [, 数据表2, …, 数据表n];

10.7 清空表

TRUNCATE TABLE 表名;

十一、数据处理-增删改

11.1 新增数据

新增数据

INSERT INTO 表名VALUES (value1,value2,....); 
INSERT INTO 表名(column1 [, column2, …, columnn])VALUES (value1 [,value2, …, valuen]);

插入查询结果

INSERT INTO 目标表名 (tar_column1 [, tar_column2, …, tar_columnn]) 
SELECT (src_column1 [, src_column2, …, src_columnn]) FROM 源表名 [WHERE condition]

11.2 更新数据

UPDATE 表名 SET 字段 = 字段值 [WHERE condition]

11.3 删除数据

DELETE FROM table_name [WHERE];

11.4 Mysql8新特性:计算列

什么叫计算列呢?简单来说就是某一列的值是通过别的列计算得来的。例如,a列值为1、b列值为2,c列不需要手动插入,定义a+b的结果为c的值,那么c就是计算列,是通过别的列计算得来的。

CREATE TABLE tb1( id INT, a INT, b INT, c INT GENERATED ALWAYS AS (a + b) VIRTUAL );

十二、数据类型

12.1 数据类型

Mysql入门_第29张图片

12.2 整数类型

 整数类型一共有 5 种,包括 TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)和 BIGINT。

Mysql入门_第30张图片

整数的可选属性有三个:

  • M

表示显示宽度,M的取值范围是(0, 255)。该项功能需要配合“ ZEROFILL ”使用,表示用“0”填满宽度,否则指定显示宽度无效。显示宽度与类型可以存储的值范围无关 。

  • UNSIGNED:

无符号类型(非负),所有的整数类型都有一个可选的属性UNSIGNED(无符号属性),无符号整数类型的最小取值为0。所以,如果需要在MySQL数据库中保存非负整数值时,可以将整数类型设置为无符号类型。

  • ZEROFILL

0填充,如果指定了ZEROFILL只是表示不够M位时,用0在左边填充,如果超过M位,只要不超过数据存储范围即可。

举例:

CREATE TABLE test_int1 ( x TINYINT, y SMALLINT, z MEDIUMINT, m INT, n BIGINT );

12.3 浮点类型

浮点数和定点数类型的特点是可以 处理小数 ,你可以把整数看成小数的一个特例。因此,浮点数和定点数的使用场景,比整数大多了。

MySQL支持的浮点数类型,分别是 FLOAT、DOUBLE、REAL。

  • FLOAT 表示单精度浮点数;
  • DOUBLE 表示双精度浮点数;
  • REAL默认就是 DOUBLE。如果你把 SQL 模式设定为启用“ REAL_AS_FLOAT ”,那 么,MySQL 就认为REAL 是 FLOAT。如果要启用“REAL_AS_FLOAT”,可以通过以下 SQL 语句实现:
SET sql_mode = “REAL_AS_FLOAT”;

浮点数类型有个缺陷,就是不精准。

因为浮点数是不准确的,所以我们要避免使用“=”来判断两个数是否相等。

CREATE TABLE test_double1(
    f1 FLOAT,
    f2 FLOAT(5,2),
    f3 DOUBLE,
    f4 DOUBLE(5,2)
);

12.4 定点数类型

MySQL中的定点数类型只有 DECIMAL 一种类型。

DECIMAL(M,D),DEC,NUMERIC

M+2字节

有效范围由M和D决定

使用 DECIMAL(M,D) 的方式表示高精度小数。其中,M被称为精度,D被称为标度。0

例如,定义DECIMAL(5,2)的类型,表示该列取值范围是-999.99~999.99。

  • DECIMAL(M,D)的最大取值范围与DOUBLE类型一样,但是有效的数据范围是由M和D决定的。
  • DECIMAL 的存储空间并不是固定的,由精度值M决定,总共占用的存储空间为M+2个字节。也就是说,在一些对精度要求不高的场景下,比起占用同样字节长度的定点数,浮点数表达的数值范围可以更大一些。
  • 定点数在MySQL内部是以 字符串 的形式进行存储,这就决定了它一定是精准的。
  • 当DECIMAL类型不指定精度和标度时,其默认为DECIMAL(10,0)。当数据的精度超出了定点数类型的精度范围时,则MySQL同样会进行四舍五入处理。

浮点数 vs 定点数

  • 浮点数相对于定点数的优点是在长度一定的情况下,浮点类型取值范围大,但是不精准,适用于需要取值范围大,又可以容忍微小误差的科学计算场景(比如计算化学、分子建模、流体动力学等)
  • 定点数类型取值范围相对小,但是精准,没有误差,适合于对精度要求极高的场景 (比如涉及金额)

举例:

CREATE TABLE test_decimal1(
    f1 DECIMAL,
    f2 DECIMAL(5,2)
);

12.5 位类型

BIT类型中存储的是二进制值,类似010110。

二进制字符串类型

长度

长度范围

占用空间

BIT(M)

M

1

约为(M + 7)/8个字节

CREATE TABLE test_bit1(
    f1 BIT,
    f2 BIT(5),
    f3 BIT(64)
);
INSERT INTO test_bit1(f2) VALUES(23);

mysql> SELECT * FROM test_bit1;
+------------+------------+------------+
| f1 | f2 | f3 |
+------------+------------+------------+
| 0x01 | NULL | NULL |
| NULL | 0x17 | NULL |
+------------+------------+------------+


mysql> SELECT BIN(f2),HEX(f2) FROM test_bit1;
+---------+---------+
| BIN(f2) | HEX(f2) |
+---------+---------+
| NULL | NULL |
| 10111 | 17 |
+---------+---------+

12.6 日期和时间类型

MySQL有多种表示日期和时间的数据类型,不同的版本可能有所差异。

MySQL8.0版本支持的日期和时间类型主要有:YEAR类型、TIME类型、DATE类型、DATETIME类型和TIMESTAMP类型。

  • YEAR 类型通常用来表示年
  • DATE 类型通常用来表示年、月、日
  • TIME 类型通常用来表示时、分、秒
  • DATETIME 类型通常用来表示年、月、日、时、分、秒
  • TIMESTAMP 类型通常用来表示带时区的年、月、日、时、分、秒

YEAR

YEAR类型用来表示年份,在所有的日期时间类型中所占用的存储空间最小,只需要 1个字节 的存储空间。

在MySQL中,YEAR有以下几种存储格式:

  • 以4位字符串或数字格式表示YEAR类型,其格式为YYYY,最小值为1901,最大值为2155。
  • 以2位字符串格式表示YEAR类型,最小值为00,最大值为99。
    • 当取值为01到69时,表示2001到2069;
    • 当取值为70到99时,表示1970到1999;
    • 当取值整数的0或00添加的话,那么是0000年;
    • 当取值是日期/字符串的'0'添加的话,是2000年。

DATE

DATE类型表示日期,没有时间部分,格式为 YYYY-MM-DD .

其中,YYYY表示年份,MM表示月份,DD表示日期。

需要 3个字节的存储空间。

在向DATE类型的字段插入数据时,同样需要满足一定的格式条件。

  • 以 YYYY-MM-DD 格式或者 YYYYMMDD 格式表示的字符串日期,其最小取值为1000-01-01,最大取值为9999-12-03。
  • YYYYMMDD格式会被转化为YYYY-MM-DD格式。
  • 以 YY-MM-DD 格式或者 YYMMDD 格式表示的字符串日期,此格式中,年份为两位数值或字符串满足YEAR类型的格式条件为:
    • 当年份取值为00到69时,会被转化为2000到2069;
    • 当年份取值为70到99时,会被转化为1970到1999。
    • 使用 CURRENT_DATE() 或者 NOW() 函数,会插入当前系统的日期。

TIME

TIME类型用来表示时间,不包含日期部分。

在MySQL中,需要 3个字节 的存储空间来存储TIME类型的数据,可以使用“HH:MM:SS”格式来表示TIME类型,其中,HH表示小时,MM表示分钟,SS表示秒。

在MySQL中,向TIME类型的字段插入数据时,也可以使用几种不同的格式。

  • 可以使用带有冒号的字符串,比如' D HH:MM:SS' 、' HH:MM:SS '、' HH:MM '、' D HH:MM '、' D HH '或' SS '格式,都能被正确地插入TIME类型的字段中。
    • 其中D表示天,其最小值为0,最大值为34。如果使用带有D格式的字符串插入TIME类型的字段时,D会被转化为小时,计算格式为D*24+HH。
    • 当使用带有冒号并且不带D的字符串表示时间时,表示当天的时间,比如12:10表示12:10:00,而不是00:12:10。
  • 可以使用不带有冒号的字符串或者数字,格式为' HHMMSS '或者 HHMMSS 。
    • 如果插入一个不合法的字符串或者数字,MySQL在存储数据时,会将其自动转化为00:00:00进行存储。比如1210,MySQL会将最右边的两位解析成秒,表示00:12:10,而不是12:10:00。
  • 使用 CURRENT_TIME() 或者 NOW() ,会插入当前系统的时间。

DATETIME

DATETIME类型在所有的日期时间类型中占用的存储空间最大,总共需要 8 个字节的存储空间。

在格式上为DATE类型和TIME类型的组合,可以表示为 YYYY-MM-DD HH:MM:SS ,其中YYYY表示年份,MM表示月份,DD表示日期,HH表示小时,MM表示分钟,SS表示秒。

在向DATETIME类型的字段插入数据时,同样需要满足一定的格式条件。

  • 以 YYYY-MM-DD HH:MM:SS 格式或者 YYYYMMDDHHMMSS 格式的字符串插入DATETIME类型的字段时,最小值为1000-01-01 00:00:00,最大值为9999-12-03 23:59:59。
  • 以YYYYMMDDHHMMSS格式的数字插入DATETIME类型的字段时,会被转化为YYYY-MM-DDHH:MM:SS格式。
  • 使用函数 CURRENT_TIMESTAMP() 和 NOW() ,可以向DATETIME类型的字段插入系统的当前日期和时间。

TIMESTAMP

TIMESTAMP类型也可以表示日期时间,其显示格式与DATETIME类型相同,都是 YYYY-MM-DD HH:MM:SS ,需要4个字节的存储空间。

但是TIMESTAMP存储的时间范围比DATETIME要小很多,只能存储“1970-01-01 00:00:01 UTC”到“2038-01-19 03:14:07 UTC”之间的时间。

其中,UTC表示世界统一时间,也叫作世界标准时间。存储数据的时候需要对当前时间所在的时区进行转换,查询数据的时候再将时间转换回当前的时区。

因此,使用TIMESTAMP存储的同一个时间值,在不同的时区查询时会显示不同的时间。

向TIMESTAMP类型的字段插入数据时,当插入的数据格式满足YY-MM-DD HH:MM:SS和YYMMDDHHMMSS时,两位数值的年份同样符合YEAR类型的规则条件,只不过表示的时间范围要小很多。

如果向TIMESTAMP类型的字段插入的时间超出了TIMESTAMP类型的范围,则MySQL会抛出错误信息。

12.7 文本字符串类型

MySQL中,文本字符串总体上分为 CHAR 、 VARCHAR 、 TINYTEXT 、 TEXT 、 MEDIUMTEXT 、LONGTEXT 、 ENUM 、 SET 等类型。

Mysql入门_第31张图片

 CHAR和VARCHAR类型都可以存储比较短的字符串。

Mysql入门_第32张图片

create table test_char1(
    c2 CHAR(5)
);

CREATE TABLE test_varchar1(
    NAME VARCHAR #错误
    NAME VARCHAR(65535) #错误     
);

在MySQL中,TEXT用来保存文本类型的字符串,总共包含4种类型,分别为TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT 类型。

Mysql入门_第33张图片

举例:

CREATE TABLE test_text(tx TEXT);
INSERT INTO test_textVALUES('atguigu ');
SELECT CHAR_LENGTH(tx) FROM test_text; #10

12.8 ENUM类型

ENUM类型也叫作枚举类型,ENUM类型的取值范围需要在定义字段时进行指定。

设置字段值时,ENUM类型只允许从成员中选取单个值,不能一次选取多个值。

其所需要的存储空间由定义ENUM类型时指定的成员个数决定。

举例:

CREATE TABLE test_enum(
    season ENUM('春','夏','秋','冬','unknow')
);

INSERT INTO test_enumVALUES('春'),('秋');
# 允许按照角标的方式获取指定索引位置的枚举值
INSERT INTO test_enumVALUES('1'),(3);

12.9 SET类型

SET类型在存储数据时成员个数越多,其占用的存储空间越大。注意:SET类型在选取成员时,可以一次选择多个成员,这一点与ENUM类型不同。

Mysql入门_第34张图片

举例:

CREATE TABLE test_set(
    s SET ('A', 'B', 'C')
);

INSERT INTO test_set (s) VALUES ('A'), ('A,B');

12.10 二进制字符串类型

MySQL中的二进制字符串类型主要存储一些二进制数据,比如可以存储图片、音频和视频等二进制数据。

MySQL中支持的二进制字符串类型主要包括BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB 和LONGBLOB类型。

BINARY与VARBINARY类型

BINARY和VARBINARY类似于CHAR和VARCHAR,只是它们存储的是二进制字符串。

  • BINARY (M)为固定长度的二进制字符串,M表示最多能存储的字节数,取值范围是0~255个字符。
    • 如果未指定(M),表示只能存储 1个字节 。例如BINARY (8),表示最多能存储8个字节,如果字段值不足(M)个字节,将在右边填充'\0'以补齐指定长度。
  • VARBINARY (M)为可变长度的二进制字符串,M表示最多能存储的字节数,总字节数不能超过行的字节长度限制65535。
    • 另外还要考虑额外字节开销,VARBINARY类型的数据除了存储数据本身外,还需要1或2个字节来存储数据的字节数。VARBINARY类型 必须指定(M) ,否则报错。

Mysql入门_第35张图片

CREATE TABLE test_binary1(
    f1 BINARY,
    f2 BINARY(3),
    # f3 VARBINARY,
    f4 VARBINARY(10)
);

INSERT INTO test_binary1(f1,f2) VALUES('a','a');
INSERT INTO test_binary1(f1,f2) VALUES('尚','尚');#失败

BLOB是一个二进制大对象 ,可以容纳可变数量的数据。

MySQL中的BLOB类型包括TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB 4种类型,它们可容纳值的最大长度不同。可以存储一个二进制的大对象,比如图片 、 音频和视频等。

需要注意的是,在实际工作中,往往不会在MySQL数据库中使用BLOB类型存储大对象数据,通常会将图片、音频和视频文件存储到 服务器的磁盘上 ,并将图片、音频和视频的访问路径存储到MySQL中。

Mysql入门_第36张图片

 举例:

CREATE TABLE test_blob1(
    id INT,
    img MEDIUMBLOB
);

12.11 JSON类型

JSON(JavaScript Object Notation)是一种轻量级的 数据交换格式 。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。

在MySQL 5.7中,就已经支持JSON数据类型。在MySQL 8.x版本中,JSON类型提供了可以进行自动验证的JSON文档和优化的存储结构,使得在MySQL中存储和读取JSON类型的数据更加方便和高效。

举例:

create table test_json(
    js JSON
);

INSERT INTO test_json (js)
VALUES ('{"name":"songhk", "age":18, "address":{"province":"beijing","city":"beijing"}}');

12.12 空间类型

MySQL 空间类型扩展支持地理特征的生成、存储和分析。

这里的地理特征表示世界上具有位置的任何东西,可以是一个实体,例如一座山;可以是空间,例如一座办公楼;也可以是一个可定义的位置,例如一个十字路口等等。

MySQL中使用 Geometry(几何) 来表示所有地理特征。

Geometry指一个点或点的集合,代表世界上任何具有位置的事物。

MySQL的空间数据类型(Spatial Data Type)对应于OpenGIS类.

包括单值类型:GEOMETRY、POINT、LINESTRING、POLYGON以及集合类型:MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、GEOMETRYCOLLECTION 。

  • Geometry是所有空间集合类型的基类,其他类型如POINT、LINESTRING、POLYGON都是Geometry的子类。
  • Point,顾名思义就是点,有一个坐标值。例如POINT(121.213342 31.234532),POINT(30 10),坐标值支持DECIMAL类型,经度(longitude)在前,维度(latitude)在后,用空格分隔。
  • LineString,线,由一系列点连接而成。如果线从头至尾没有交叉,那就是简单的(simple);如果起点和终点重叠,那就是封闭的(closed)。例如LINESTRING(30 10,10 30,4040),点与点之间用逗号分隔,一个点中的经纬度用空格分隔,与POINT格式一致。

Mysql入门_第37张图片

 十三、约束

13.1 概念

数据完整性(Data Integrity)是指数据的精确性(Accuracy)和可靠性(Reliability)。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而提出的。

为了保证数据的完整性,SQL规范以约束的方式对表数据进行额外的条件限制。从以下四个方面考虑:

  • 实体完整性(Entity Integrity) :例如,同一个表中,不能存在两条完全相同无法区分的记录
  • 域完整性(Domain Integrity) :例如:年龄范围0-120,性别范围“男/女”
  • 引用完整性(Referential Integrity) :例如:员工所在部门,在部门表中要能找到这个部门
  • 用户自定义完整性(User-defined Integrity) :例如:用户名唯一、密码不能为空等,本部门经理的工资不得高于本部门职工的平均工资的5倍。

约束是表级的强制规定。可以在创建表时规定约束(通过 CREATE TABLE 语句),或者在表创建之后通过 ALTER TABLE 语句规定约束。

约束分类

  • 根据约束数据列的限制,约束可分为:
    • 单列约束:每个约束只约束一列
    • 多列约束:每个约束可约束多列数据
  • 根据约束的作用范围,约束可分为:
    • 列级约束:只能作用在一个列上,跟在列的定义后面
    • 表级约束:可以作用在多个列上,不与列一起,而是单独定义
  • 根据约束起的作用,约束可分为:
    • NOT NULL 非空约束,规定某个字段不能为空
    • UNIQUE 唯一约束,规定某个字段在整个表中是唯一的
    • PRIMARY KEY 主键(非空且唯一)约束
    • FOREIGN KEY 外键约束
    • CHECK 检查约束
    • DEFAULT 默认值约束

13.2 非空约束

13.2.1 作用

限定某个字段/某列的值不允许为空

13.2.2 关键字

NOT NULL

13.2.3 特点

  • 默认,所有的类型的值都可以是NULL,包括INT、FLOAT等数据类型
  • 非空约束只能出现在表对象的列上,只能某个列单独限定非空,不能组合非空
  • 一个表可以有很多列都分别限定了非空
  • 空字符串''不等于NULL,0也不等于NULL

13.2.4 添加非空约束

建表时:

CREATE TABLE 表名称( 
    字段名 数据类型, 
    字段名 数据类型 NOT NULL, 
    字段名 数据类型 NOT NULL 
); 

建表后:

alter table 表名称 modify 字段名 数据类型 not null

13.2.5 删除非空约束

alter table 表名称 modify 字段名 数据类型 NULL;

alter table 表名称 modify 字段名 数据类型;

13.3 唯一性约束

13.3.1 作用

用来限制某个字段/某列的值不能重复。

13.3.2 关键字

UNIQUE

13.3.3 特点

  • 同一个表可以有多个唯一约束。
  • 唯一约束可以是某一个列的值唯一,也可以多个列组合的值唯一。
  • 唯一性约束允许列值为空。
  • 在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同。
  • MySQL会给唯一约束的列上默认创建一个唯一索引。

13.3.4 添加唯一约束

建表时:

create table 表名称(
    字段名 数据类型,
    字段名 数据类型 unique,
    字段名 数据类型 unique key,
    字段名 数据类型
);
create table 表名称(
    字段名 数据类型,
    字段名 数据类型,
    字段名 数据类型,
    [constraint 约束名] unique key(字段名)
);

建表后:

alter table 表名称 add unique key(字段列表);

alter table 表名称 modify 字段名 字段类型 unique;

13.3.5 复合唯一约束

create table 表名称(
    字段名 数据类型,
    字段名 数据类型,
    字段名 数据类型,
    unique key(字段列表) #字段列表中写的是多个字段名,多个字段名用逗号分隔,表示那么是复合唯一,即多
个字段的组合是唯一的
);

13.3.6 删除唯一约束

  • 添加唯一性约束的列上也会自动创建唯一索引。
  • 删除唯一约束只能通过删除唯一索引的方式删除。
  • 删除时需要指定唯一索引名,唯一索引名就和唯一约束名一样。
  • 如果创建唯一约束时未指定名称,如果是单列,就默认和列名相同;如果是组合列,那么默认和()中排在第一个的列名相同。也可以自定义唯一性约束名。
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名'; #查看都有哪些约束
show index from 表名称; 查看表的索引

ALTER TABLE USE RDROP INDEX uk_name_pwd;

13.4 主键约束

13.4.1 作用

用来唯一标识表中的一行记录。

13.4.2 关键字

primary key

13.4.3 特点

  • 主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现空值。
  • 一个表最多只能有一个主键约束,建立主键约束可以在列级别创建,也可以在表级别上创建。
  • 主键约束对应着表中的一列或者多列(复合主键)
  • 如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复。
  • MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也没用。
  • 当创建主键约束时,系统默认会在所在的列或列组合上建立对应的主键索引(能够根据主键查询的,就根据主键查询,效率更高)。如果删除主键约束了,主键约束对应的索引就自动删除了。
  • 需要注意的一点是,不要修改主键字段的值。因为主键是数据记录的唯一标识,如果修改了主键的值,就有可能会破坏数据的完整性。

13.4.4 添加主键约束

建表时:

create table 表名称(
    字段名 数据类型 primary key,
    字段名 数据类型
);
create table 表名称(
    字段名 数据类型,
    字段名 数据类型,
    字段名 数据类型,
    [constraint 约束名] primary key(字段名) #表级模式
);

建表后:

ALTER TABLE 表名称 ADD PRIMARY KEY(字段列表); #字段列表可以是一个字段,也可以是多个字段,如果是多个字段的话,是复合主键

13.4.5 复合主键约束

create table 表名称(
    字段名 数据类型,
    字段名 数据类型,
    字段名 数据类型,
    primary key(字段名1,字段名2) #表示字段1和字段2的组合是唯一的,也可以有更多个字段
);

13.4.6 删除主键约束

alter table 表名称 drop primary key;

13.5 自增列

13.5.1 作用

某个字段的值自增

13.5.2 关键字

auto_increment

13.5.3 特点

  • 一个表最多只能有一个自增长列
  • 当需要产生唯一标识符或顺序值时,可设置自增长
  • 自增长列约束的列必须是键列
  • 自增约束的列的数据类型必须是整数类型
  • 如果自增列指定了 0 和 null,会在当前最大值的基础上自增。如果自增列手动指定了具体值,直接赋值为具体值。

13.5.4 指定自增约束

建表前:

create table 表名称(
    字段名 数据类型 primary key auto_increment,
    字段名 数据类型 unique key not null,
    字段名 数据类型 unique key,
    字段名 数据类型 not null default 默认值
);

建表后:

alter table 表名称 modify 字段名 数据类型 auto_increment;

13.5.5 删除自增约束

alter table 表名称 modify 字段名 数据类型; #去掉auto_increment相当于删除

13.6 外键约束

13.6.1 作用

限定某个表的某个字段的引用完整性。

比如:员工表的员工所在部门的选择,必须在部门表能找到对应的部分。

13.6.2 关键字

FOREIGN KEY

13.6.3 主表和从表

  • 主表(父表):被引用的表,被参考的表
  • 从表(子表):引用别人的表,参考别人的表

例如:员工表的员工所在部门这个字段的值要参考部门表:部门表是主表,员工表是从表。

例如:学生表、课程表、选课表:选课表的学生和课程要分别参考学生表和课程表,学生表和课程表是主表,选课表是从表。

13.6.4 特点

  • 从表的外键列,必须引用/参考主表的主键或唯一约束的列:因为被依赖/被参考的值必须是唯一的
  • 在创建外键约束时,如果不给外键约束命名,默认名不是列名,而是自动产生一个外键名(例如student_ibfk_1;),也可以指定外键约束名。
  • 创建(CREATE)表时就指定外键约束的话,先创建主表,再创建从表
  • 删表时,先删从表(或先删除外键约束),再删除主表
  • 当主表的记录被从表参照时,主表的记录将不允许删除,如果要删除数据,需要先删除从表中依赖该记录的数据,然后才可以删除主表的数据
  • 在“从表”中指定外键约束,并且一个表可以建立多个外键约束
  • 从表的外键列与主表被参照的列名字可以不相同,但是数据类型必须一样,逻辑意义一致。如果类型不一样,创建子表时,就会出现错误“ERROR 1005 (HY000): Can't create table'database.tablename'(errno: 150)”。例如:都是表示部门编号,都是int类型。
  • 删除外键约束后,必须 手动 删除对应的索引

13.6.5 添加外键约束

建表时:

create table 主表名称(
    字段1 数据类型 primary key,
    字段2 数据类型
);
create table 从表名称(
    字段1 数据类型 primary key,
    字段2 数据类型,
    [CONSTRAINT <外键约束名称>] FOREIGN KEY(从表的某个字段) references 主表名(被参考字段)
);

建表后:

ALTER TABLE 从表名 ADD [CONSTRAINT 约束名] FOREIGN KEY (从表的字段) REFERENCES 主表名(被引用字段) [on update xx][on delete xx];

13.6.6 约束等级

  • Cascade方式 :在父表上update/delete记录时,同步update/delete掉子表的匹配记录
  • Set null方式 :在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能为not null
  • No action方式 :如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
  • Restrict方式 :同no action, 都是立即检查外键约束
  • Set default方式 (在可视化工具SQLyog中可能显示空白):父表有变更时,子表将外键列设置成一个默认的值,但Innodb不能识别

比如:

create table emp(
    eid int primary key, #员工编号
    ename varchar(5), #员工姓名
    deptid int, #员工所在的部门
    foreign key (deptid) references dept(did) on update cascade on delete set null
    #把修改操作设置为级联修改等级,把删除操作设置为set null等级
);

13.6.7 删除外键约束

SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称';#查看某个表的约束名 ALTER TABLE 从表名 DROP FOREIGN KEY 外键约束名;

13.7 检查约束

13.7.1 作用

检查某个字段的值是否符号xx要求,一般指的是值的范围

13.7.2 关键字

CHECK

13.7.3 说明

MySQL5.7 可以使用check约束,但check约束对数据验证没有任何作用。添加数据时,没有任何错误或警告但是MySQL 8.0中可以使用check约束了。

CREATE TABLE temp(
    ename varchar(5),
    gender char check ('男' or '女')
);

13.8 默认值约束

13.8.1 作用

给某个字段/某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默认值。

13.8.2 关键字

DEFAULT

13.8.3 添加默认值

create table 表名称(
    字段名 数据类型 primary key,
    字段名 数据类型 unique key not null,
    字段名 数据类型 unique key,
    字段名 数据类型 not null default 默认值
);

alter table 表名称 modify 字段名 数据类型 default 默认值;

13.8.4 删除默认值约束

alter table 表名称 modify 字段名 数据类型 ;#删除默认值约束,也不保留非空约束
alter table 表名称 modify 字段名 数据类型 not null; #删除默认值约束,保留非空约束

十四、视图

14.1 常见的数据库对象

Mysql入门_第38张图片

14.2 视图概述

视图是一种 虚拟表 ,本身是不具有数据的,占用很少的内存空间,它是 SQL 中的一个重要概念。

视图建立在已有表的基础上, 视图赖以建立的这些表称为基表。

视图的创建和删除只影响视图本身,不影响对应的基表。但是当对视图中的数据进行增加、删除和修改操作时,数据表中的数据会相应地发生变化,反之亦然。

14.3 创建视图

CREATE [OR REPLACE]
[ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
VIEW 视图名称 [(字段列表)]
AS 查询语句
[WITH [CASCADED|LOCAL] CHECK OPTION]

-- 精简版
CREATE VIEW 视图名称AS 查询语句

举例:

CREATE VIEW dept_sum_vu
(name, minsal, maxsal, avgsal)
AS
SELECT d.department_name, MIN(e.salary), MAX(e.salary),AVG(e.salary)
FROM employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY d.department_name;

14.4 查看视图

语法1:查看数据库的表对象、视图对象

SHOW TABLES;

语法2:查看视图的结构

DESC 视图名称;

语法3:查看视图的属性信息

SHOW TABLE STATUS LIKE '视图名称'

执行结果显示,注释Comment为VIEW,说明该表为视图,其他的信息为NULL,说明这是一个虚表。

语法4:查看视图的详细定义信息

SHOW CREATE VIEW 视图名称;

14.5 更新视图的数据

当视图数据和基表数据一对一时

MySQL支持使用INSERT、UPDATE和DELETE语句对视图中的数据进行插入、更新和删除操作。

当视图中的数据发生变化时,数据表中的数据也会发生变化,反之亦然。

要使视图可更新,视图中的行和底层基本表中的行之间必须存在 一对一 的关系。

另外当视图定义出现如下情况时,视图不支持更新操作:

  • 在定义视图的时候指定了“ALGORITHM = TEMPTABLE”,视图将不支持INSERT和DELETE操作;
  • 视图中不包含基表中所有被定义为非空又未指定默认值的列,视图将不支持INSERT操作;
  • 在定义视图的SELECT语句中使用了 JOIN联合查询 ,视图将不支持INSERT和DELETE操作;
  • 在定义视图的SELECT语句后的字段列表中使用了 数学表达式 或子查询 ,视图将不支持INSERT,也不支持UPDATE使用了数学表达式、子查询的字段值;
  • 在定义视图的SELECT语句后的字段列表中使用 DISTINCT 、 聚合函数 、 GROUP BY 、 HAVING 、UNION 等,视图将不支持INSERT、UPDATE、DELETE;
  • 在定义视图的SELECT语句中包含了子查询,而子查询中引用了FROM后面的表,视图将不支持INSERT、UPDATE、DELETE;
  • 视图定义基于一个 不可更新视图 ;常量视图。

14.6 修改删除视图

修改方式1:使用CREATE OR REPLACE VIEW 子句修改视图

CREATE OR REPLACE VIEW empvu80
(id_number, name, sal, department_id)
AS
SELECT employee_id, first_name || ' ' || last_name, salary, department_id
FROM employees
WHERE department_id = 80;

修改方式2:ALTER VIEW

ALTER VIEW 视图名称
AS
查询语句

删除视图:

DROP VIEW IF EXISTS 视图名称;
DROP VIEW 视图名称;

十五、存储过程和函数

15.1 存储过程概述

15.1.1 理解

存储过程的英文是 Stored Procedure 。它的思想很简单,就是一组经过 预先编译 的 SQL 语句的封装。

执行过程:存储过程预先存储在 MySQL 服务器上,需要执行的时候,客户端只需要向服务器端发出调用存储过程的命令,服务器端就可以把预先存储好的这一系列 SQL 语句全部执行。

15.2 创建存储过程

15.2.1 语法分析

语法:

CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...)
[characteristics ...]
BEGIN
    存储过程体
END

类似java中方法:

修饰符 返回类型 方法名(参数类型 参数名,...){
    方法体;
}

说明:

1、参数前面的符号的意思

  • IN :当前参数为输入参数,也就是表示入参;存储过程只是读取这个参数的值。如果没有定义参数种类, 默认就是 IN ,表示输入参数。
  • OUT :当前参数为输出参数,也就是表示出参;执行完成之后,调用这个存储过程的客户端或者应用程序就可以读取这个参数返回的值了。
  • INOUT :当前参数既可以为输入参数,也可以为输出参数。

2、形参类型可以是 MySQL数据库中的任意类型。

3、characteristics 表示创建存储过程时指定的对存储过程的约束条件,其取值信息如下:

  • LANGUAGE SQL :说明存储过程执行体是由SQL语句组成的,当前系统支持的语言为SQL。
  • [NOT] DETERMINISTIC :指明存储过程执行的结果是否确定。
    • DETERMINISTIC表示结果是确定的。每次执行存储过程时,相同的输入会得到相同的输出。
    • NOT DETERMINISTIC表示结果是不确定的,相同的输入可能得到不同的输出。
    • 如果没有指定任意一个值,默认为NOT DETERMINISTIC。
  • { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } :指明子程序使用SQL语句的限制。
    • CONTAINS SQL表示当前存储过程的子程序包含SQL语句,但是并不包含改写数据的SQL语句;
    • NO SQL表示当前存储过程的子程序中不包含任何SQL语句;
    • READS SQL DATA表示当前存储过程的子程序中包含读数据的SQL语句;
    • MODIFIES SQL DATA表示当前存储过程的子程序中包含写数据的SQL语句。
    • 默认情况下,系统会指定为CONTAINS SQL。
  • SQL SECURITY { DEFINER | INVOKER } :执行当前存储过程的权限,即指明哪些用户能够执行当前存储过程。
    • DEFINER 表示只有当前存储过程的创建者或者定义者才能执行当前存储过程;、
    • INVOKER 表示拥有当前存储过程的访问权限的用户能够执行当前存储过程。
    • 如果没有设置相关的值,则MySQL默认指定值为DEFINER。

4、存储过程体中可以有多条 SQL 语句,如果仅仅一条SQL 语句,则可以省略 BEGIN 和 END。

编写存储过程并不是一件简单的事情,可能存储过程中需要复杂的 SQL 语句。

1. BEGIN…END:BEGIN…END 中间包含了多个语句,每个语句都以(;)号为结束符。
2. DECLARE:DECLARE 用来声明变量,使用的位置在于 BEGIN…END 语句中间,而且需要在其他语句使用之前进
行变量的声明。
3. SET:赋值语句,用于对变量进行赋值。
4. SELECT… INTO:把从数据表中查询的结果存放到变量中,也就是为变量赋值。

5、需要设置新的结束标记

DELIMITER 新的结束标记

因为MySQL默认的语句结束符号为分号‘;’。为了避免与存储过程中SQL语句结束符相冲突,需要使用DELIMITER改变存储过程的结束符。

比如:“DELIMITER //”语句的作用是将MySQL的结束符设置为//,并以“END //”结束存储过程。存储过程定义完毕之后再使用“DELIMITER ;”恢复默认结束符。DELIMITER也可以指定其他符号作为结束符。当使用DELIMITER命令时,应该避免使用反斜杠(‘\’)字符,因为反斜线是MySQL的转义字符。

15.2.2 代码举例

举例1:创建无参数存储过程

DELIMITER $
CREATE PROCEDURE select_all_data()
BEGIN
SELECT * FROM emps;
END $
DELIMITER ;

举例2:创建有入参存储过程

DELIMITER //
CREATE PROCEDURE show_someone_salary(IN empname VARCHAR(20))
BEGIN
SELECT salary FROM emps WHERE ename = empname;
END //
DELIMITER ;

举例3:创建有出参存储过程

DELIMITER //
CREATE PROCEDURE show_min_salary(OUT ms DOUBLE)
BEGIN
SELECT MIN(salary) INTO ms FROM emps;
END //
DELIMITER ;

举例4:创建有INOUT参数存储过程

DELIMITER //
CREATE PROCEDURE show_mgr_name(INOUT empname VARCHAR(20))
BEGIN
SELECT ename INTO empname FROM emps
WHERE eid = (SELECT MID FROM emps WHERE ename=empname);
END //
DELIMITER ;

15.3 调用存储过程

调用格式存储过程有多种调用方法。存储过程必须使用CALL语句调用,并且存储过程和数据库相关,如果要执行其他数据库中的存储过程,需要指定数据库名称,例如CALL dbname.procname。

CALL 存储过程名(实参列表)

15.3.1 调用格式

1、调用in模式的参数:

CALL sp1('值');

2、调用out模式的参数:

SET @name=null; 
CALL sp1(@name); 
SELECT @name;

3、调用inout模式的参数:

SET @name=值;
CALL sp1(@name);
SELECT @name;

15.3.2 代码举例

举例:

DELIMITER //
CREATE PROCEDURE CountProc(IN sid INT,OUT num INT)
BEGIN
SELECT COUNT(*) INTO num FROM fruits
WHERE s_id = sid;
END //
DELIMITER ;

15.4 函数的使用

MySQL支持自定义函数,定义好之后,调用方式与调用MySQL预定义的系统函数一样。

15.4.1 语法分析

学过的函数:LENGTH、SUBSTR、CONCAT等

语法格式:

CREATE FUNCTION 函数名(参数名 参数类型,...) RETURNS 返回值类型 [characteristics ...] BEGIN 函数体 #函数体中肯定有 RETURN 语句 END

说明:

1、参数列表:指定参数为IN、OUT或INOUT只对PROCEDURE是合法的,FUNCTION中总是默认为IN参数。

2、RETURNS type 语句表示函数返回数据的类型;RETURNS子句只能对FUNCTION做指定,对函数而言这是 强制 的。它用来指定函数的返回类型,而且函数体必须包含一个 RETURN value 语句。

3、characteristic 创建函数时指定的对函数的约束。取值与创建存储过程时相同,这里不再赘述。

4、函数体也可以用BEGIN…END来表示SQL代码的开始和结束。如果函数体只有一条语句,也可以省略BEGIN…END。

15.4.2 调用函数

在MySQL中,存储函数的使用方法与MySQL内部函数的使用方法是一样的。

SELECT 函数名(实参列表)

15.4.3 代码举例

不带参数函数:

CREATE FUNCTION email_by_name()
RETURNS VARCHAR(25)
DETERMINISTIC
CONTAINS SQL
BEGIN
    RETURN (SELECT email FROM employees WHERE last_name = 'Abel');
END //
DELIMITER ;
SELECT email_by_name();

带参数函数:

DELIMITER //
CREATE FUNCTION email_by_id(emp_id INT)
RETURNS VARCHAR(25)
DETERMINISTIC
CONTAINS SQL
BEGIN
    RETURN (SELECT email FROM employees WHERE employee_id = emp_id);
END //
DELIMITER ;
SELECT email_by_id(102);

15.4.4 对比存储过程和函数

关键字

调用语法

返回值

应用场景

存储过程

PROCEDURE

CALL 存储过程()

理解为有0个或多个

一般用于更新

存储函数

FUNCTION

SELECT 函数()

只能是一个

一般用于查询结果为一个值并返回时

15.5 存储过程和函数的删改查

15.5.1 查看

1. 使用SHOW CREATE语句查看存储过程和函数的创建信息

SHOW CREATE {PROCEDURE | FUNCTION} 存储过程名或函数名

2. 使用SHOW STATUS语句查看存储过程和函数的状态信息

SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']

3. 从information_schema.Routines表中查看存储过程和函数的信息

SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME='存储过程或函数的名' [AND ROUTINE_TYPE = {'PROCEDURE|FUNCTION'}];

15.5.2 修改

ALTER {PROCEDURE | FUNCTION} 存储过程或函数的名 [characteristic ...]

其中,characteristic指定存储过程或函数的特性,其取值信息与创建存储过程、函数时的取值信息略有不同。

{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
  • CONTAINS SQL ,表示子程序包含SQL语句,但不包含读或写数据的语句。
  • NO SQL ,表示子程序中不包含SQL语句。
  • READS SQL DATA ,表示子程序中包含读数据的语句。
  • MODIFIES SQL DATA ,表示子程序中包含写数据的语句。
  • SQL SECURITY { DEFINER | INVOKER } ,指明谁有权限来执行。
    • DEFINER ,表示只有定义者自己才能够执行。
    • INVOKER ,表示调用者可以执行。COMMENT 'string' ,表示注释信息。
  • COMMENT 'string' ,表示注释信息

15.5.3 删除

删除存储过程和函数,可以使用DROP语句,其语法结构如下:

DROP {PROCEDURE | FUNCTION} [IF EXISTS] 存储过程或函数的名

15.6 存储过程的优缺点

15.6.1 优点

1、存储过程可以一次编译多次使用。

存储过程只在创建时进行编译,之后的使用都不需要重新编译,这就提升了 SQL 的执行效率。

2、可以减少开发工作量。

将代码 封装 成模块,实际上是编程的核心思想之一,这样可以把复杂的问题拆解成不同的模块,然后模块之间可以 重复使用 ,在减少开发工作量的同时,还能保证代码的结构清晰。

3、存储过程的安全性强。

我们在设定存储过程的时候可以 设置对用户的使用权限 ,这样就和视图一样具有较强的安全性。

4、可以减少网络传输量。

因为代码封装到存储过程中,每次使用只需要调用存储过程即可,这样就减少了网络传输量。

5、良好的封装性。

在进行相对复杂的数据库操作时,原本需要使用一条一条的 SQL 语句,可能要连接多次数据库才能完成的操作,现在变成了一次存储过程,只需要 连接一次即可 。

15.6.2 缺点

1、可移植性差。

存储过程不能跨数据库移植,比如在 MySQL、Oracle 和 SQL Server 里编写的存储过程,在换成其他数据库时都需要重新编写。

2、调试困难。

只有少数 DBMS 支持存储过程的调试。对于复杂的存储过程来说,开发和维护都不容易。虽然也有一些第三方工具可以对存储过程进行调试,但要收费。

3、存储过程的版本管理很困难。

比如数据表索引发生变化了,可能会导致存储过程失效。我们在开发软件的时候往往需要进行版本管理,但是存储过程本身没有版本控制,版本迭代更新的时候很麻烦。

4、不适合高并发的场景。

高并发的场景需要减少数据库的压力,有时数据库会采用分库分表的方式,而且对可扩展性要求很高,在这种情况下,存储过程会变得难以维护, 增加数据库的压力 ,显然就不适用了。

十六、变量、流程控制、游标

16.1 变量

在MySQL数据库的存储过程和函数中,可以使用变量来存储查询或计算的中间结果数据,或者输出最终的结果数据。

在 MySQL 数据库中,变量分为 系统变量 以及 用户自定义变量 。

16.1.1 系统变量

变量由系统定义,不是用户定义,属于 服务器 层面。

启动MySQL服务,生成MySQL服务实例期间,MySQL将为MySQL服务器内存中的系统变量赋值,这些系统变量定义了当前MySQL服务实例的属性、特征。

这些系统变量的值要么是 编译MySQL时参数 的默认值,要么是 配置文件 (例如my.ini等)中的参数值。

可以通过网址 https://dev.mysql.com/doc/refman/8.0/en/server-systemvariables.html 查看MySQL文档的系统变量。

16.1.1.1 系统变量分类

系统变量分为全局系统变量(需要添加 global 关键字)以及会话系统变量(需要添加 session 关键字)。

有时也把全局系统变量简称为全局变量,有时也把会话系统变量称为local变量。如果不写,默认会话级别。

静态变量(在 MySQL 服务实例运行期间它们的值不能使用 set 动态修改)属于特殊的全局系统变量。

16.1.1.2 查看修改系统变量

#查看所有全局变量
SHOW GLOBAL VARIABLES;

#查看所有会话变量
SHOW SESSION VARIABLES;
SHOW VARIABLES;

#查看满足条件的部分系统变量。
SHOW GLOBAL VARIABLES LIKE '%标识符%';

#查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%标识符%';

#查看指定的系统变量的值
SELECT @@global.变量名;、

#查看指定的会话变量的值
SELECT @@session.变量名;
SELECT @@变量名;

#修改全局变量值
SET @@global.变量名=变量值;
SET GLOBAL 变量名=变量值;

#会话变量赋值
SET @@session.变量名=变量值;
SET SESSION 变量名=变量值;

举例:

SELECT @@global.autocommit;
SET GLOBAL autocommit=0;

16.1.2 用户变量

用户变量是用户自己定义的,作为 MySQL 编码规范,MySQL 中的用户变量以 一个“@” 开头。

根据作用范围不同,又分为 会话用户变量 和 局部变量 。

16.1.2.1 会话用户变量

#变量定义
#方式1:“=”或“:=”
SET @用户变量 = 值;
SET @用户变量 := 值;

#方式2:“:=” 或 INTO关键字
SELECT @用户变量 := 表达式 [FROM 等子句];
SELECT 表达式 INTO @用户变量 [FROM 等子句];

#查看用户变量
SELECT @用户变量

举例:

SELECT @num := COUNT(*) FROM employees;
SELECT @num;

SELECT AVG(salary) INTO @avgsalary FROM employees;
SELECT @avgsalary;

16.1.2.2 局部变量

定义:可以使用 DECLARE 语句定义一个局部变量作用域:

仅仅在定义它的 BEGIN ... END 中有效位置:

只能放在 BEGIN ... END 中,而且只能放在第一句。

BEGIN
    #声明局部变量
    DECLARE 变量名1 变量数据类型 [DEFAULT 变量默认值];
    DECLARE 变量名2,变量名3,... 变量数据类型 [DEFAULT 变量默认值];
    #为局部变量赋值
    SET 变量名1 = 值;
    SELECT 值 INTO 变量名2 [FROM 子句];
    #查看局部变量的值
    SELECT 变量1,变量2,变量3;
END

举例:

DELIMITER //
CREATE PROCEDURE set_value()
BEGIN
    DECLARE emp_name VARCHAR(25);
    DECLARE sal DOUBLE(10,2);
    SELECT last_name,salary INTO emp_name,sal
    FROM employees
    WHERE employee_id = 102;
    SELECT emp_name,sal;
END //
DELIMITER 

16.2 定义条件和处理程序

定义条件 是事先定义程序执行过程中可能遇到的问题, 处理程序 定义了在遇到问题时应当采取的处理方式,并且保证存储过程或函数在遇到警告或错误时能继续执行。

这样可以增强存储程序处理问题的能力,避免程序异常停止运行。

说明:定义条件和处理程序在存储过程、存储函数中都是支持的。

16.2.1 定义条件

定义条件就是给MySQL中的错误码命名,这有助于存储的程序代码更清晰。

它将一个 错误名字 和 指定的错误条件 关联起来。

这个名字可以随后被用在定义处理程序的 DECLARE HANDLER 语句中。

定义条件使用DECLARE语句,语法格式如下:

DECLARE 错误名称 CONDITION FOR 错误码(或错误条件)

错误码的说明:MySQL_error_code 和 sqlstate_value 都可以表示MySQL的错误。

  • MySQL_error_code是数值类型错误代码。
  • sqlstate_value是长度为5的字符串类型错误代码。
  • 例如,在ERROR 1418 (HY000)中,1418是MySQL_error_code,'HY000'是sqlstate_value。

举例1:定义“Field_Not_Be_NULL”错误名与MySQL中违反非空约束的错误类型是“ERROR 1048 (23000)”对应。

#使用MySQL_error_code
DECLARE Field_Not_Be_NULL CONDITION FOR 1048;
#使用sqlstate_value
DECLARE Field_Not_Be_NULL CONDITION FOR SQLSTATE '23000';

16.2.2 定义处理程序

可以为SQL执行过程中发生的某种类型的错误定义特殊的处理程序。

定义处理程序时,使用DECLARE语句的语法如下:

DECLARE 处理方式 HANDLER FOR 错误类型 处理语句
  • 处理方式:处理方式有3个取值:CONTINUE、EXIT、UNDO。
    • CONTINUE :表示遇到错误不处理,继续执行。
    • EXIT :表示遇到错误马上退出。
    • UNDO :表示遇到错误后撤回之前的操作。MySQL中暂时不支持这样的操作。
  • 错误类型(即条件)可以有如下取值:
    • SQLSTATE '字符串错误码' :表示长度为5的sqlstate_value类型的错误代码;
    • MySQL_error_code :匹配数值类型错误代码;
    • 错误名称 :表示DECLARE ... CONDITION定义的错误条件名称。
    • SQLWARNING :匹配所有以01开头的SQLSTATE错误代码;
    • NOT FOUND :匹配所有以02开头的SQLSTATE错误代码;
    • SQLEXCEPTION :匹配所有没有被SQLWARNING或NOT FOUND捕获的SQLSTATE错误代码;
  • 处理语句:如果出现上述条件之一,则采用对应的处理方式,并执行指定的处理语句。语句可以是像“ SET 变量 = 值 ”这样的简单语句,也可以是使用 BEGIN ... END 编写的复合语句。

举例:

#方法1:捕获sqlstate_value
DECLARE CONTINUE HANDLER FOR SQLSTATE '42S02' SET @info = 'NO_SUCH_TABLE';

#方法2:捕获mysql_error_value
DECLARE CONTINUE HANDLER FOR 1146 SET @info = 'NO_SUCH_TABLE';

#方法3:先定义条件,再调用
DECLARE no_such_table CONDITION FOR 1146;
DECLARE CONTINUE HANDLER FOR NO_SUCH_TABLE SET @info = 'NO_SUCH_TABLE';
 
#方法4:使用SQLWARNING
DECLARE EXIT HANDLER FOR SQLWARNING SET @info = 'ERROR';

#方法5:使用NOT FOUND
DECLARE EXIT HANDLER FOR NOT FOUND SET @info = 'NO_SUCH_TABLE';
 
#方法6:使用SQLEXCEPTION
DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info = 'ERROR';

16.2.3 案例解决

在存储过程中,定义处理程序,捕获sqlstate_value值,当遇到MySQL_error_code值为1048时,执行CONTINUE操作,并且将@proc_value的值设置为-1。

DELIMITER //
CREATE PROCEDURE UpdateDataNoCondition()
BEGIN
    #定义处理程序
    DECLARE CONTINUE HANDLER FOR 1048 SET @proc_value = -1;
    SET @x = 1;
    UPDATE employees SET email = NULL WHERE last_name = 'Abel';
    SET @x = 2;
    UPDATE employees SET email = 'aabbel' WHERE last_name = 'Abel';
    SET @x = 3;
END //
DELIMITER ;

说明:即使email不能为空会报错1048,但因为定义了处理程序,仍会执行完毕。

输出结果:

mysql> CALL UpdateDataWithCondition();
Query OK, 0 rows affected (0.01 sec)
mysql> SELECT @x,@proc_value;
+------+-------------+
| @x | @proc_value |
+------+-------------+
| 3 | -1 |
+------+-------------+
1 row in set (0.00 sec)

16.3 流程控制

解决复杂问题不可能通过一个 SQL 语句完成,我们需要执行多个 SQL 操作。

流程控制语句的作用就是控制存储过程中 SQL 语句的执行顺序,是我们完成复杂操作必不可少的一部分。

只要是执行的程序,流程就分为三大类:

  • 顺序结构 :程序从上往下依次执行
  • 分支结构 :程序按条件进行选择执行,从两条或多条路径中选择一条执行
  • 循环结构 :程序满足一定条件下,重复执行一组语句

针对于MySQL 的流程控制语句主要有 3 类。

  • 条件判断语句 :IF 语句和 CASE 语句
  • 循环语句 :LOOP、WHILE 和 REPEAT 语句
  • 跳转语句 :ITERATE 和 LEAVE 语句

16.3.1 分支结构IF

语法结构是:

IF 表达式1 THEN 操作1
[ELSEIF 表达式2 THEN 操作2]……
[ELSE 操作N]
END IF

举例:

DELIMITER //
create function fun2(n int)
returns int
    DETERMINISTIC
    CONTAINS SQL
begin
    DECLARE result INT DEFAULT 0;
    DECLARE value INT DEFAULT 100;
    DECLARE value2 INT DEFAULT 200;

    if n >=5 then
        set result:= value * n;
    else
         set result:= value2 * n;
    end if;
    return result;
end //
DELIMITER ;

16.3.2 分支结构CASE

语法结构是:

#情况一:类似于switch
CASE 表达式
WHEN 值1 THEN 结果1或语句1(如果是语句,需要加分号)
WHEN 值2 THEN 结果2或语句2(如果是语句,需要加分号)
...
ELSE 结果n或语句n(如果是语句,需要加分号)
END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)

 
#情况二:类似于多重if
CASE
WHEN 条件1 THEN 结果1或语句1(如果是语句,需要加分号)
WHEN 条件2 THEN 结果2或语句2(如果是语句,需要加分号)
...
ELSE 结果n或语句n(如果是语句,需要加分号)
END [case](如果是放在begin end中需要加上case,如果放在select后面不需要)

16.3.3 循环结构LOOP

LOOP循环语句用来重复执行某些语句。LOOP内的语句一直重复执行直到循环被退出(使用LEAVE子句),跳出循环过程。

loop_label:LOOP
    //do something
    //if ... LEAVE loop_label  跳出循环
END LOOP [loop_label]

举例:

DELIMITER //
CREATE PROCEDURE update_salary_loop(OUT num INT)
BEGIN
    DECLARE avg_salary DOUBLE;
    DECLARE loop_count INT DEFAULT 0;    
    SELECT AVG(salary) INTO avg_salary FROM employees;
    
    label_loop:LOOP
    IF avg_salary >= 12000 THEN LEAVE label_loop;
    END IF;
    UPDATE employees SET salary = salary * 1.1;
    SET loop_count = loop_count + 1;
    SELECT AVG(salary) INTO avg_salary FROM employees;
    END LOOP label_loop;
    
    SET num = loop_count;
END //
DELIMITER ;

16.3.4 循环结构WHILE

WHILE语句创建一个带条件判断的循环过程。

WHILE在执行语句执行时,先对指定的表达式进行判断,如果为真,就执行循环内的语句,否则退出循环。

WHILE语句的基本格式如下:

[while_label:] WHILE 循环条件 DO
循环体
END WHILE [while_label];

举例:

DELIMITER //
CREATE PROCEDURE test_while()
BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE i < 10 DO
    SET i = i + 1;
    END WHILE;
    SELECT i;
END //
DELIMITER ;
#调用
CALL test_while();

16.3.5 循环结构REPEAT

REPEAT语句创建一个带条件判断的循环过程。

与WHILE循环不同的是,REPEAT 循环首先会执行一次循环,然后在 UNTIL 中进行表达式的判断,如果满足条件就退出,即 END REPEAT;如果条件不满足,则会就继续执行循环,直到满足退出条件为止。

同Java中的DO... WHILE

[repeat_label:] REPEAT
循环体
UNTIL 结束循环的条件表达式
END REPEAT [repeat_label]

举例:

DELIMITER //
CREATE PROCEDURE test_repeat()
BEGIN
    DECLARE i INT DEFAULT 0;
    REPEAT
    SET i = i + 1;
    UNTIL i >= 10
    END REPEAT;
    SELECT i;
END //
DELIMITER ;

16.3.6 跳转语句LEAVE

LEAVE语句:可以用在循环语句内,或者以 BEGIN 和 END 包裹起来的程序体内,表示跳出循环或者跳出程序体的操作。

如果有面向过程的编程语言的使用经验,可以把 LEAVE 理解为 break。

LEAVE 标记名

举例:

DELIMITER //
CREATE PROCEDURE leave_begin(IN num INT)
begin_label: BEGIN
    IF num<=0
    THEN LEAVE begin_label;
    ELSEIF num=1
    THEN SELECT AVG(salary) FROM employees;
    ELSEIF num=2
    THEN SELECT MIN(salary) FROM employees;
    ELSE
    SELECT MAX(salary) FROM employees;
    END IF;    
    SELECT COUNT(*) FROM employees;
END //
DELIMITER ;

16.3.7 跳转语句ITERATE

ITERATE语句:只能用在循环语句(LOOP、REPEAT和WHILE语句)内,表示重新开始循环,将执行顺序转到语句段开头处。

如果有面向过程的编程语言的使用经验,可以把 ITERATE 理解为 continue,意思为“再次循环”。

ITERATE label

举例:

DELIMITER //
CREATE PROCEDURE test_iterate()
BEGIN
DECLARE num INT DEFAULT 0;
my_loop:LOOP
    SET num = num + 1;
    IF num < 10
    THEN ITERATE my_loop;
    ELSEIF num > 15
    THEN SELECT MIN(salary) FROM employees;
    ELSE
    SELECT MAX(salary) FROM employees;
    END IF;    
    SELECT COUNT(*) FROM employees;
    END LOOP my_loop;
END //
DELIMITER ;

16.4 游标

16.4.1 游标概念

虽然可以通过筛选条件 WHERE 和 HAVING,或者是限定返回记录的关键字 LIMIT 返回一条记录。但是却无法在结果集中像指针一样,向前定位一条记录、向后定位一条记录,或者是随意定位到某一条记录 ,并对记录的数据进行处理。

游标,提供了一种灵活的操作方式,能够对结果集中的每一条记录进行定位,并对指向的记录中的数据进行操作的数据结构。

游标让 SQL 这种面向集合的语言有了面向过程开发的能力。

在 SQL 中,游标是一种临时的数据库对象,可以指向存储在数据库表中的数据行指针。这里游标充当了指针的作用 ,我们可以通过操作游标来对数据行进行操作。

MySQL中游标可以在存储过程和函数中使用。

16.4.2 使用游标步骤

游标必须在声明处理程序之前被声明,并且变量和条件还必须在声明游标或处理程序之前被声明。

如果我们想要使用游标,一般需要经历四个步骤。不同的 DBMS 中,使用游标的语法可能略有不同。

第一步,声明游标

DECLARE cursor_name CURSOR FOR select_statement;

举例:

DECLARE cur_emp CURSOR FOR SELECT employee_id,salary FROM employees;

第二步,打开游标

OPEN cursor_name

当定义好游标之后,如果想要使用游标,必须先打开游标。打开游标的时候 SELECT 语句的查询结果集就会送到游标工作区,为后面游标的 逐条读取 结果集中的记录做准备。

举例:

OPEN cur_emp ;

第三步,使用游标(从游标中取得数据)

FETCH cursor_name INTO var_name [, var_name] ...

这句的作用是使用 cursor_name 这个游标来读取当前行,并且将数据保存到 var_name 这个变量中,游标指针指到下一行。

如果游标读取的数据行有多个列名,则在 INTO 关键字后面赋值给多个变量名即可。注意:var_name必须在声明游标之前就定义好。

FETCH cur_emp INTO emp_id, emp_sal ;

注意:游标的查询结果集中的字段数,必须跟 INTO 后面的变量数一致,否则,在存储过程执行的时候,MySQL 会提示错误。

第四步,关闭游标

CLOSE cursor_name

有 OPEN 就会有 CLOSE,也就是打开和关闭游标。当我们使用完游标后需要关闭掉该游标。因为游标会占用系统资源 ,如果不及时关闭,游标会一直保持到存储过程结束,影响系统运行的效率。

16.4.3 举例

创建存储过程“get_count_by_limit_total_salary()”,声明IN参数 limit_total_salary,DOUBLE类型;声明OUT参数total_count,INT类型。

函数的功能可以实现累加薪资最高的几个员工的薪资值,直到薪资总和达到limit_total_salary参数的值,返回累加的人数给total_count。

DELIMITER //
CREATE PROCEDURE get_count_by_limit_total_salary(IN limit_total_salary DOUBLE,OUT
 total_count INT)
BEGIN
    DECLARE sum_salary DOUBLE DEFAULT 0; #记录累加的总工资
    DECLARE cursor_salary DOUBLE DEFAULT 0; #记录某一个工资值
    DECLARE emp_count INT DEFAULT 0; #记录循环个数
  
    #定义游标
    DECLARE emp_cursor CURSOR FOR SELECT salary FROM employees ORDER BY salary DESC;
    #打开游标
    OPEN emp_cursor;
    
    REPEAT
        #使用游标(从游标中获取数据)
        FETCH emp_cursor INTO cursor_salary;
        SET sum_salary = sum_salary + cursor_salary;
        SET emp_count = emp_count + 1;
    UNTIL sum_salary >= limit_total_salary
    END REPEAT;
    
    SET total_count = emp_count;
    #关闭游标
    CLOSE emp_cursor;
END //
DELIMITER ;

16.4.4 小结

游标是 MySQL 的一个重要的功能,为 逐条读取 结果集中的数据,提供了完美的解决方案。

跟在应用层面实现相同的功能相比,游标可以在存储程序中使用,效率高,程序也更加简洁。

但同时也会带来一些性能问题,比如在使用游标的过程中,会对数据行进 加锁 ,这样在业务并发量大的时候,不仅会影响业务之间的效率,还会 消耗系统资源 ,造成内存不足,这是因为游标是在内存中进行的处理。

建议:养成用完之后就关闭的习惯,这样才能提高系统的整体效率。

十七、触发器

17.1 触发器概述

MySQL从 5.0.2 版本开始支持触发器。

MySQL的触发器和存储过程一样,都是嵌入到MySQL服务器的一段程序。

触发器是由 事件来触发 某个操作,这些事件包括 INSERT 、 UPDATE 、 DELETE 事件。

所谓事件就是指用户的动作或者触发某项行为。如果定义了触发程序,当数据库执行这些语句时候,就相当于事件发生了,就会 自动 激发触发器执行相应的操作。

当对数据表中的数据执行插入、更新和删除操作,需要自动执行一些数据库逻辑时,可以使用触发器来实现。

17.2 创建触发器

创建触发器的语法结构是:

CREATE TRIGGER 触发器名称
{BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON 表名
FOR EACH ROW
触发器执行的语句块;

说明:

  • 表名 :表示触发器监控的对象。
  • BEFORE|AFTER :表示触发的时间。BEFORE 表示在事件之前触发;AFTER 表示在事件之后触发。
  • INSERT|UPDATE|DELETE :表示触发的事件。
    • INSERT 表示插入记录时触发;
    • UPDATE 表示更新记录时触发
    • DELETE 表示删除记录时触发

举例1:

1、创建数据表:

CREATE TABLE test_trigger (
    id INT PRIMARY KEY AUTO_INCREMENT,
    t_note VARCHAR(30)
);


CREATE TABLE test_trigger_log (
    id INT PRIMARY KEY AUTO_INCREMENT,
    t_log VARCHAR(30)
);

2、创建触发器:创建名称为before_insert的触发器,向test_trigger数据表插入数据之前,向test_trigger_log数据表中插入before_insert的日志信息。

DELIMITER //
CREATE TRIGGER before_insert
BEFORE INSERT ON test_trigger
FOR EACH ROW
BEGIN
    INSERT INTO test_trigger_log (t_log)
 VALUES('before_insert');
END //
DELIMITER ;

3、向test_trigger数据表中插入数据

INSERT INTO test_trigger (t_note) VALUES ('测试 BEFORE INSERT 触发器');

4、查看test_trigger_log数据表中的数据

mysql> SELECT * FROM test_trigger_log;
+----+---------------+
| id | t_log |
+----+---------------+
| 1 | before_insert |
+----+---------------+
1 row in set (0.00 sec)

举例2:

定义触发器“salary_check_trigger”,基于员工表“employees”的INSERT事件,在INSERT之前检查将要添加的新员工薪资是否大于他领导的薪资,如果大于领导薪资,则报sqlstate_value为'HY000'的错误,从而使得添加失败。

DELIMITER //
CREATE TRIGGER salary_check_trigger
BEFORE INSERT ON employees FOR EACH ROW
BEGIN
    DECLARE mgrsalary DOUBLE;
    SELECT salary INTO mgrsalary FROM employees WHERE employee_id = NEW.manager_id;
    IF NEW.salary > mgrsalary THEN
        SIGNAL SQLSTATE 'HY000' SET MESSAGE_TEXT = '薪资高于领导薪资错误';
    END IF;
END //
DELIMITER ;

上面触发器声明过程中的NEW关键字代表INSERT添加语句的新记录。

17.3 查看触发器

查看触发器是查看数据库中已经存在的触发器的定义、状态和语法信息等。

SHOW TRIGGERS\G
SHOW CREATE TRIGGER 触发器名
SELECT * FROM information_schema.TRIGGERS;

17.4 删除触发器

触发器也是数据库对象,删除触发器也用DROP语句,语法格式如下:

DROP TRIGGER IF EXISTS 触发器名称;

17.5 触发器优缺点

优点:

  • 触发器可以确保数据的完整性。
  • 触发器可以帮助我们记录操作日志。
  • 触发器还可以用在操作数据前,对数据进行合法性检查。

缺点:

  • 触发器最大的一个问题就是可读性差。
  • 相关数据的变更,可能会导致触发器出错。

你可能感兴趣的:(mysql,数据库,数据仓库)