本文最后更新于:2025年8月5日 下午
MySQL 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database Management System:关系数据库管理系统)应用软件之一。本文记录 MySQL 的基本知识。
概述
数据库
数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。
每个数据库都有一个或多个不同的 API 用于创建,访问,管理,搜索和复制所保存的数据。
也可以将数据存储在文件中,但是在文件中读写数据速度相对较慢。
所以,现在我们使用关系型数据库管理系统(RDBMS)来存储和管理大数据量。所谓的关系型数据库,是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。
RDBMS 即关系数据库管理系统(Relational Database Management System)的特点:
-
数据以表格的形式出现
-
每行为各种记录名称
-
每列为记录名称所对应的数据域
-
许多的行和列组成一张表单
-
若干的表单组成database
RDBMS 术语
先了解下RDBMS的一些术语:
- 数据库: 数据库是一些关联表的集合。
- 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。
- 列: 一列(数据元素) 包含了相同类型的数据, 例如邮政编码的数据。
- 行: 一行(元组,或记录)是一组相关的数据,例如一条用户订阅的数据。
- 冗余:存储两倍数据,冗余降低了性能,但提高了数据的安全性。
- 主键:主键是唯一的。一个数据表中只能包含一个主键。你可以使用主键来查询数据。
- 外键:外键用于关联两个表。
- 复合键:复合键(组合键)将多个列作为一个索引键,一般用于复合索引。
- 索引:使用索引可快速访问数据库表中的特定信息。索引是对数据库表中一列或多列的值进行排序的一种结构。类似于书籍的目录。
- 参照完整性: 参照的完整性要求关系中不允许引用不存在的实体。与实体完整性是关系模型必须满足的完整性约束条件,目的是保证数据的一致性。
MySQL 为关系型数据库(Relational Database Management System), 这种所谓的"关系型"可以理解为"表格"的概念, 一个关系型数据库由一个或数个表格组成, 如图所示的一个表格:
-
表头(header): 每一列的名称;
-
列(col): 具有相同数据类型的数据的集合;
-
行(row): 每一行用来描述某条记录的具体信息;
-
值(value): 行的具体信息, 每个值必须与该列的数据类型相同;
-
键(key): 键的值在当前列中具有唯一性。
-
元组:元组(tuple)是关系数据库中的基本概念,关系是一张表,表中的每行(即数据库中的每条记录)就是一个元组,每列就是一个属性。 在二维表里,元组也称为行。
-
码:码就是能唯一标识实体的属性,对应表中的列。
-
候选码:若关系中的某一属性或属性组的值能唯一的标识一个元组,而其任何、子集都不能再标识,则称该属性组为候选码。例如:在学生实体中,“学号”是能唯一的区分学生实体的,同时又假设“姓名”、“班级”的属性组合足以区分学生实体,那么{学号}和{姓名,班级}都是候选码。
-
主码 : 主码也叫主键。主码是从候选码中选出来的。 一个实体集中只能有一个主码,但可以有多个候选码。
-
外码 : 外码也叫外键。如果一个关系中的一个属性是另外一个关系中的主码则这个属性为外码。
-
主属性:候选码中出现过的属性称为主属性。比如关系 工人(工号,身份证号,姓名,性别,部门). 显然工号和身份证号都能够唯一标示这个关系,所以都是候选码。工号、身份证号这两个属性就是主属性。如果主码是一个属性组,那么属性组中的属性都是主属性。
-
非主属性: 不包含在任何一个候选码中的属性称为非主属性。比如在关系——学生(学号,姓名,年龄,性别,班级)中,主码是“学号”,那么其他的“姓名”、“年龄”、“性别”、“班级”就都可以称为非主属性。
MySQL数据库
MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
- MySQL 是开源的,目前隶属于 Oracle 旗下产品。
- MySQL 支持大型的数据库。可以处理拥有上千万条记录的大型数据库。
- MySQL 使用标准的 SQL 数据语言形式。
- MySQL 可以运行于多个系统上,并且支持多种语言。这些编程语言包括 C、C++、Python、Java、Perl、PHP、Eiffel、Ruby 和 Tcl 等。
- MySQL 对 PHP 有很好的支持,PHP 是很适合用于 Web 程序开发。
- MySQL 支持大型数据库,支持 5000 万条记录的数据仓库,32 位系统表文件最大可支持 4GB,64 位系统支持最大的表文件为8TB。
- MySQL 是可以定制的,采用了 GPL 协议,你可以修改源码来开发自己的 MySQL 系统。
MySQL 管理
Windows 系统下
启动 MySQL 服务器:
1、通过 “服务” 管理工具: 打开"运行"对话框(Win + R),输入 services.msc,找到"MySQL"服务,右击选择"启动"。
2、通过命令提示符: 打开命令提示符(以管理员身份),输入以下命令:
1 |
|
关闭MySQL服务器:
1、**通过 “服务” 管理工具:**同样打开"运行"对话框,输入 services.msc,找到 “MySQL” 服务,右击选择"停止"。
2、通过命令提示符: 打开命令提示符(以管理员身份),输入以下命令:
1 |
|
Linux 系统下
1、启动 MySQL 服务:
使用 systemd命令(适用于大多数现代 Linux 发行版,如 Ubuntu、CentOS 等):
1 |
|
使用 service 命令(在一些较旧的发行版中):
1 |
|
2、关闭 MySQL 服务:
使用 systemd:
1 |
|
使用 service 命令:
1 |
|
3、重启 MySQL 服务:
使用 systemd:
1 |
|
使用 service 命令:
1 |
|
4、检查 MySQL 服务状态:
使用 systemd命令:
1 |
|
使用 service 命令:
1 |
|
Mac OS 系统
启动 MySQL 服务:
使用命令行:
1 |
|
关闭 MySQL 服务:
使用命令行:
1 |
|
重启 MySQL 服务:
使用命令行:
1 |
|
检查 MySQL 服务状态:
使用命令行:
1 |
|
以上命令中,mysql 可能会因为安装路径或版本的不同而有所变化。
在 Mac OS 中,MySQL 的安装路径通常是 /usr/local/mysql/,因此启动和关闭 MySQL 服务需要使用这个路径下的 mysql.server 脚本。
相关知识
数据库范式
数据库范式有 3 种:
- 1NF(第一范式):属性不可再分。
- 2NF(第二范式):1NF 的基础之上,消除了非主属性对于码的部分函数依赖。
- 3NF(第三范式):3NF 在 2NF 的基础之上,消除了非主属性对于码的传递函数依赖 。
1NF(第一范式)
属性(对应于表中的字段)不能再被分割,也就是这个字段只能是一个值,不能再分为多个其他的字段了。1NF 是所有关系型数据库的最基本要求 ,也就是说关系型数据库中创建的表一定满足第一范式。
2NF(第二范式)
2NF 在 1NF 的基础之上,消除了非主属性对于码的部分函数依赖。如下图所示,展示了第一范式到第二范式的过渡。第二范式在第一范式的基础上增加了一个列,这个列称为主键,非主属性都依赖于主键。
一些重要的概念:
- 函数依赖(functional dependency):若在一张表中,在属性(或属性组)X 的值确定的情况下,必定能确定属性 Y 的值,那么就可以说 Y 函数依赖于 X,写作 X → Y。
- 部分函数依赖(partial functional dependency):如果 X→Y,并且存在 X 的一个真子集 X0,使得 X0→Y,则称 Y 对 X 部分函数依赖。比如学生基本信息表 R 中(学号,身份证号,姓名)当然学号属性取值是唯一的,在 R 关系中,(学号,身份证号)->(姓名),(学号)->(姓名),(身份证号)->(姓名);所以姓名部分函数依赖于(学号,身份证号);
- 完全函数依赖(Full functional dependency):在一个关系中,若某个非主属性数据项依赖于全部关键字称之为完全函数依赖。比如学生基本信息表 R(学号,班级,姓名)假设不同的班级学号有相同的,班级内学号不能相同,在 R 关系中,(学号,班级)->(姓名),但是(学号)->(姓名)不成立,(班级)->(姓名)不成立,所以姓名完全函数依赖与(学号,班级);
- 传递函数依赖:在关系模式 R(U)中,设 X,Y,Z 是 U 的不同的属性子集,如果 X 确定 Y、Y 确定 Z,且有 X 不包含 Y,Y 不确定 X,(X∪Y)∩Z=空集合,则称 Z 传递函数依赖(transitive functional dependency) 于 X。传递函数依赖会导致数据冗余和异常。传递函数依赖的 Y 和 Z 子集往往同属于某一个事物,因此可将其合并放到一个表中。比如在关系 R(学号 , 姓名, 系名,系主任)中,学号 → 系名,系名 → 系主任,所以存在非主属性系主任对于学号的传递函数依赖。
3NF(第三范式)
3NF 在 2NF 的基础之上,消除了非主属性对于码的传递函数依赖 。符合 3NF 要求的数据库设计,基本上解决了数据冗余过大,插入异常,修改异常,删除异常的问题。比如在关系 R(学号 , 姓名, 系名,系主任)中,学号 → 系名,系名 → 系主任,所以存在非主属性系主任对于学号的传递函数依赖,所以该表的设计,不符合 3NF 的要求。
主键和外键
主键(主码):主键用于唯一标识一个元组,不能有重复,不允许为空。一个表只能有一个主键。
外键(外码):外键用来和其他表建立联系用,外键是另一表的主键,外键是可以有重复的,可以是空值。一个表可以有多个外键。
为什么不推荐使用外键与级联
对于外键和级联,阿里巴巴开发手册这样说到:
【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
说明: 以学生和成绩的关系为例,学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。
如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度
外键与级联的缺点:
- 增加了复杂性: a. 每次做 DELETE 或者 UPDATE 都必须考虑外键约束,会导致开发的时候很痛苦, 测试数据极为不方便; b. 外键的主从关系是定的,假如哪天需求有变化,数据库中的这个字段根本不需要和其他表有关联的话就会增加很多麻烦。
- 增加了额外工作:数据库需要增加维护外键的工作,比如当我们做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,保证数据的的一致性和正确性,这样会不得不消耗数据库资源。如果在应用层面去维护的话,可以减小数据库压力;
- 对分库分表不友好:因为分库分表下外键是无法生效的。
外键与级联的好处:
- 保证了数据库数据的一致性和完整性;
- 级联操作方便,减轻了程序代码量;
所以说,不要一股脑的就抛弃了外键这个概念,既然它存在就有它存在的道理,如果系统不涉及分库分表,并发量不是很高的情况还是可以考虑使用外键的。
SQL 分类
数据定义语言(DDL)
数据定义语言(Data Definition Language,DDL)是 SQL 语言集中负责数据结构定义与数据库对象定义的语言。
DDL 的主要功能是定义数据库对象。
DDL 的核心指令是 CREATE
、ALTER
、DROP
。
数据操纵语言(DML)
数据操纵语言(Data Manipulation Language, DML)是用于数据库操作,对数据库其中的对象和数据运行访问工作的编程语句。
DML 的主要功能是 访问数据,因此其语法都是以读写数据库为主。
DML 的核心指令是 INSERT
、UPDATE
、DELETE
、SELECT
。这四个指令合称 CRUD(Create, Read, Update, Delete),即增删改查。
事务控制语言(TCL)
事务控制语言 (Transaction Control Language, TCL) 用于管理数据库中的事务。这些用于管理由 DML 语句所做的更改。它还允许将语句分组为逻辑事务。
TCL 的核心指令是 COMMIT
、ROLLBACK
。
数据控制语言(DCL)
数据控制语言 (Data Control Language, DCL) 是一种可对数据访问权进行控制的指令,它可以控制特定用户账户对数据表、查看表、预存程序、用户自定义函数等数据库对象的控制权。
DCL 的核心指令是 GRANT
、REVOKE
。
DCL 以控制用户的访问权限为主,因此其指令作法并不复杂,可利用 DCL 控制的权限有:CONNECT
、SELECT
、INSERT
、UPDATE
、DELETE
、EXECUTE
、USAGE
、REFERENCES
。
根据不同的 DBMS 以及不同的安全性实体,其支持的权限控制也有所不同。
我们先来介绍 DML 语句用法。 DML 的主要功能是读写数据库实现增删改查。
MySQL 用户设置
在 MySQL 中,用户设置包括创建用户、设置权限、管理用户等操作。以下是一些常用的 MySQL 用户设置操作,包括创建用户、设置权限、查看和删除用户等。
创建用户
要创建一个新用户,你可以使用以下 SQL 命令:
1 |
|
username
:用户名。host
:指定用户可以从哪些主机连接。例如,localhost
仅允许本地连接,%
允许从任何主机连接。password
:用户的密码。
实例
1 |
|
授权权限
创建用户后,你需要授予他们访问权限,使用 GRANT 命令来授予权限:
1 |
|
privileges
:所需的权限,如ALL PRIVILEGES
、SELECT
、INSERT
、UPDATE
、DELETE
等。database_name.*
:表示对某个数据库或表授予权限。database_name.*
表示对整个数据库的所有表授予权限,database_name.table_name
表示对指定的表授予权限。TO 'username'@'host'
:指定授予权限的用户和主机。
实例
1 |
|
刷新权限
授予或撤销权限后,需要刷新权限使更改生效:
1 |
|
- 举例:在数据库 test 上新建一位只读用户 reader
1 |
|
查看用户权限
要查看特定用户的权限,可以使用以下命令:
1 |
|
实例
1 |
|
撤销权限
要撤销用户的权限,使用 REVOKE 命令:
1 |
|
实例
1 |
|
删除用户
如果需要删除用户,可以使用以下命令:
1 |
|
实例
1 |
|
修改用户密码
要修改用户的密码,可以使用 ALTER USER 命令:
1 |
|
实例
1 |
|
修改用户主机
要更改用户的主机(即允许从哪些主机连接),可以先删除用户,再重新创建一个新的用户。
实例
- 删除旧用户
1 |
|
- 重新创建用户并指定新的主机
1 |
|
创建用户时指定权限
在创建用户时,也可以同时授予权限(在 MySQL 8.0.16 及更高版本):
实例
1 |
|
/etc/my.cnf 文件配置
/etc/my.cnf
文件是 MySQL 配置文件,用于配置 MySQL 服务器的各种参数和选项。
一般情况下,不需要修改该配置文件,该文件默认配置如下:
1 |
|
在配置文件中,你可以指定不同的错误日志文件存放的目录,一般你不需要改动这些配置。
/etc/my.cnf
文件在不同的系统和 MySQL 版本中可能有所不同,但是一般包含以下几个部分:
基本设置
basedir
: MySQL 服务器的基本安装目录。datadir
: 存储 MySQL 数据文件的位置。socket
: MySQL 服务器的 Unix 套接字文件路径。pid-file
: 存储当前运行的 MySQL 服务器进程 ID 的文件路径。port
: MySQL 服务器监听的端口号,默认是 3306。
服务器选项
bind-address
: 指定 MySQL 服务器监听的 IP 地址,可以是 IP 地址或主机名。server-id
: 在复制配置中,为每个 MySQL 服务器设置一个唯一的标识符。default-storage-engine
: 默认的存储引擎,例如 InnoDB 或 MyISAM。max_connections
: 服务器可以同时维持的最大连接数。thread_cache_size
: 线程缓存的大小,用于提高新连接的启动速度。query_cache_size
: 查询缓存的大小,用于提高相同查询的效率。default-character-set
: 默认的字符集。collation-server
: 服务器的默认排序规则。
性能调优
innodb_buffer_pool_size
: InnoDB 存储引擎的缓冲池大小,这是 InnoDB 性能调优中最重要的参数之一。key_buffer_size
: MyISAM 存储引擎的键缓冲区大小。table_open_cache
: 可以同时打开的表的缓存数量。thread_concurrency
: 允许同时运行的线程数。
安全设置
skip-networking
: 禁止 MySQL 服务器监听网络连接,仅允许本地连接。skip-grant-tables
: 以无需密码的方式启动 MySQL 服务器,通常用于恢复忘记的 root 密码,但这是一个安全风险。auth_native_password=1
: 启用 MySQL 5.7 及以上版本的原生密码认证。
日志设置
log_error
: 错误日志文件的路径。general_log
: 记录所有客户端连接和查询的日志。slow_query_log
: 记录执行时间超过特定阈值的慢查询。log_queries_not_using_indexes
: 记录未使用索引的查询。
复制设置
master_host
和master_user
: 主服务器的地址和复制用户。master_password
: 复制用户的密码。master_log_file
和master_log_pos
: 用于复制的日志文件和位置。
管理MySQL的命令
以下列出了使用Mysql数据库过程中常用的命令:
-
USE 数据库名 :
选择要操作的Mysql数据库,使用该命令后所有Mysql命令都只针对该数据库。1
2mysql> use RUNOOB;
Database changed -
SHOW DATABASES:
列出 MySQL 数据库管理系统的数据库列表。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| RUNOOB |
| cdcol |
| mysql |
| onethink |
| performance_schema |
| phpmyadmin |
| test |
| wecenter |
| wordpress |
+--------------------+
10 rows in set (0.02 sec) -
SHOW TABLES:
显示指定数据库的所有表,使用该命令前需要使用 use 命令来选择要操作的数据库。1
2
3
4
5
6
7
8
9
10
11mysql> use RUNOOB;
Database changed
mysql> SHOW TABLES;
+------------------+
| Tables_in_runoob |
+------------------+
| employee_tbl |
| runoob_tbl |
| tcount_tbl |
+------------------+
3 rows in set (0.00 sec) -
SHOW COLUMNS FROM *数据表*:
显示数据表的属性,属性类型,主键信息 ,是否为 NULL,默认值等其他信息。1
2
3
4
5
6
7
8
9
10mysql> SHOW COLUMNS FROM runoob_tbl;
+-----------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+---------+-------+
| runoob_id | int(11) | NO | PRI | NULL | |
| runoob_title | varchar(255) | YES | | NULL | |
| runoob_author | varchar(255) | YES | | NULL | |
| submission_date | date | YES | | NULL | |
+-----------------+--------------+------+-----+---------+-------+
4 rows in set (0.01 sec) -
SHOW INDEX FROM *数据表*:
显示数据表的详细索引信息,包括PRIMARY KEY(主键)。1
2
3
4
5
6
7mysql> SHOW INDEX FROM runoob_tbl;
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| runoob_tbl | 0 | PRIMARY | 1 | runoob_id | A | 2 | NULL | NULL | | BTREE | | |
+------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec) -
SHOW TABLE STATUS [FROM db_name] [LIKE ‘pattern’] \G:
该命令将输出Mysql数据库管理系统的性能及统计信息。1
2
3
4mysql> SHOW TABLE STATUS FROM RUNOOB; # 显示数据库 RUNOOB 中所有表的信息
mysql> SHOW TABLE STATUS from RUNOOB LIKE 'runoob%'; # 表名以runoob开头的表的信息
mysql> SHOW TABLE STATUS from RUNOOB LIKE 'runoob%'\G; # 加上 \G,查询结果按列打印
MySQL 连接
您可以使用 MySQL 二进制方式进入到 mysql 命令提示符下来连接 MySQL 数据库,格式如下:
1 |
|
参数说明:
-u
参数用于指定用户名。-p
参数表示需要输入密码。
以下是从命令行中连接 mysql 服务器的简单实例:
1 |
|
按照提示输入密码,并按下 Enter 键。
在登录成功后会出现 mysql> 命令提示窗口,你可以在上面执行任何 SQL 语句。
视图(VIEW)
定义:
- 视图是基于 SQL 语句的结果集的可视化的表。
- 视图是虚拟的表,本身不包含数据,也就不能对其进行索引操作。对视图的操作和对普通表的操作一样。
作用:
- 简化复杂的 SQL 操作,比如复杂的联结;
- 只使用实际表的一部分数据;
- 通过只给用户访问视图的权限,保证数据的安全性;
- 更改数据格式和表示。
创建视图
1 |
|
游标
游标(cursor)是一个存储在 DBMS 服务器上的数据库查询,它不是一条 SELECT
语句,而是被该语句检索出来的结果集。
在存储过程中使用游标可以对一个结果集进行移动遍历。
游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改。
使用游标的几个明确步骤:
-
在使用游标前,必须声明(定义)它。这个过程实际上没有检索数据, 它只是定义要使用的
SELECT
语句和游标选项。 -
一旦声明,就必须打开游标以供使用。这个过程用前面定义的 SELECT 语句把数据实际检索出来。
-
对于填有数据的游标,根据需要取出(检索)各行。
-
在结束游标使用时,必须关闭游标,可能的话,释放游标(有赖于具
体的 DBMS)。
数据库操作
创建数据库
我们可以在登陆 MySQL 服务后,使用 create 命令创建数据库,语法如下:
1 |
|
以下命令简单的演示了创建数据库的过程,数据名为 RUNOOB:
1 |
|
建数据库的基本语法如下:
1 |
|
如果你希望在创建数据库时指定一些选项,可以使用 CREATE DATABASE 语句的其他参数,例如,你可以指定字符集和排序规则:
1 |
|
如果数据库已经存在,执行 CREATE DATABASE 将导致错误。
为了避免这种情况,你可以在 CREATE DATABASE 语句中添加 IF NOT EXISTS 子句:
1 |
|
删除数据库
使用普通用户登陆 MySQL 服务器,你可能需要特定的权限来创建或者删除 MySQL 数据库,所以我们这边使用 root 用户登录,root 用户拥有最高权限。
在删除数据库过程中,务必要十分谨慎,因为在执行删除命令后,所有数据将会消失。
drop 命令删除数据库
drop 命令格式:
1 |
|
参数说明:
IF EXISTS
是一个可选的子句,表示如果数据库存在才执行删除操作,避免因为数据库不存在而引发错误。database_name
是你要删除的数据库的名称。
例如删除名为 RUNOOB 的数据库:
1 |
|
注意: 在执行删除数据库操作前,请确保你确实想要删除数据库及其所有数据,因为该操作是不可逆的。为了避免误操作,通常建议在执行删除之前备份数据库。
选择数据库
在你连接到 MySQL 数据库后,可能有多个可以操作的数据库,所以你需要选择你要操作的数据库。
从命令提示窗口中选择 MySQL 数据库
在 mysql> 提示窗口中可以很简单的选择特定的数据库。
在 MySQL 中,要选择要使用的数据库,可以使用 USE 语句,以下是基本的语法:
1 |
|
参数说明:
- database_name 是你要选择的数据库的名称。
选择来数据库后,你的后续 SQL 查询和操作在指定的数据库 database_name 上执行。
MySQL 数据类型
MySQL 中定义数据字段的类型对你数据库的优化是非常重要的。
MySQL 支持多种类型,大致可以分为三类:数值、日期/时间和字符串(字符)类型。
数值类型
MySQL 支持所有标准 SQL 数值数据类型。
这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL 和 NUMERIC),以及近似数值数据类型(FLOAT、REAL 和 DOUBLE PRECISION)。
关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词。
BIT数据类型保存位字段值,并且支持 MyISAM、MEMORY、InnoDB 和 BDB表。
作为 SQL 标准的扩展,MySQL 也支持整数类型 TINYINT、MEDIUMINT 和 BIGINT。下面的表显示了需要的每个整数类型的存储和范围。
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT | 1 Bytes | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 Bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT | 3 Bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 Bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT | 8 Bytes | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT | 4 Bytes | (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE | 8 Bytes | (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) | 双精度 浮点数值 |
DECIMAL | 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 | 依赖于M和D的值 | 依赖于M和D的值 | 小数值 |
日期和时间类型
表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。
每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
TIMESTAMP类型有专有的自动更新特性,将在后面描述。
类型 | 大小 ( bytes) | 范围 | 格式 | 用途 |
---|---|---|---|---|
DATE | 3 | 1000-01-01/9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3 | ‘-838:59:59’/‘838:59:59’ | HH:MM:SS | 时间值或持续时间 |
YEAR | 1 | 1901/2155 | YYYY | 年份值 |
DATETIME | 8 | ‘1000-01-01 00:00:00’ 到 ‘9999-12-31 23:59:59’ | YYYY-MM-DD hh:mm:ss | 混合日期和时间值 |
TIMESTAMP | 4 | ‘1970-01-01 00:00:01’ UTC 到 ‘2038-01-19 03:14:07’ UTC结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYY-MM-DD hh:mm:ss | 混合日期和时间值,时间戳 |
字符串类型
字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255 bytes | 定长字符串 |
VARCHAR | 0-65535 bytes | 变长字符串 |
TINYBLOB | 0-255 bytes | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255 bytes | 短文本字符串 |
BLOB | 0-65 535 bytes | 二进制形式的长文本数据 |
TEXT | 0-65 535 bytes | 长文本数据 |
MEDIUMBLOB | 0-16 777 215 bytes | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215 bytes | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295 bytes | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295 bytes | 极大文本数据 |
注意:char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。
CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。
BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。
BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。
有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。
枚举与集合类型(Enumeration and Set Types)
- ENUM: 枚举类型,用于存储单一值,可以选择一个预定义的集合。
- SET: 集合类型,用于存储多个值,可以选择多个预定义的集合。
空间数据类型(Spatial Data Types)
GEOMETRY, POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION: 用于存储空间数据(地理信息、几何图形等)。
数据表操作
创建数据表
创建 MySQL 数据表需要以下信息:
- 表名
- 表字段名
- 定义每个表字段的数据类型
语法
以下为创建 MySQL 数据表的 SQL 通用语法:
1 |
|
参数说明:
table_name
是你要创建的表的名称。column1
,column2
, … 是表中的列名。datatype
是每个列的数据类型。
以下是一个具体的实例,创建一个用户表 users:
1 |
|
实例解析:
id
: 用户 id,整数类型,自增长,作为主键。username
: 用户名,变长字符串,不允许为空。email
: 用户邮箱,变长字符串,不允许为空。birthdate
: 用户的生日,日期类型。is_active
: 用户是否已经激活,布尔类型,默认值为 true。
以上只是一个简单的实例,用到了一些常见的数据类型包括 INT, VARCHAR, DATE, BOOLEAN,你可以根据实际需要选择不同的数据类型。AUTO_INCREMENT 关键字用于创建一个自增长的列,PRIMARY KEY 用于定义主键。
如果你希望在创建表时指定数据引擎,字符集和排序规则等,可以使用 CHARACTER SET 和 COLLATE 子句:
1 |
|
以上代码创建一个使用 utf8mb4 字符集和 utf8mb4_general_ci 排序规则的表。
以下例子中我们将在 RUNOOB 数据库中创建数据表 runoob_tbl:
1 |
|
实例解析:
- 如果你不想字段为空可以设置字段的属性为 NOT NULL,如上实例中的 runoob_title 与 runoob_author 字段, 在操作数据库时如果输入该字段的数据为空,就会报错。
- AUTO_INCREMENT 定义列为自增的属性,一般用于主键,数值会自动加 1。
- PRIMARY KEY 关键字用于定义列为主键。 您可以使用多列来定义主键,列间以逗号 , 分隔。
- ENGINE 设置存储引擎,CHARSET 设置编码。
删除数据表
MySQL中删除数据表是非常容易操作的,但是你在进行删除表操作时要非常小心,因为执行删除命令后所有数据都会消失。
语法
以下为删除 MySQL 数据表的通用语法:
1 |
|
或
1 |
|
参数说明:
table_name
是要删除的表的名称。IF EXISTS
是一个可选的子句,表示如果表存在才执行删除操作,避免因为表不存在而引发错误。
1 |
|
请替换 mytable 为你要删除的表的名称。
如果你只是想删除表中的所有数据,但保留表的结构,可以使用 TRUNCATE TABLE 语句:
1 |
|
这会清空表中的所有数据,但不会删除表本身。
注意事项:
- 备份数据:在删除表之前,确保已经备份了数据,如果你需要的话。
- 外键约束:如果该表与其他表有外键约束,可能需要先删除外键约束,或者确保依赖关系被处理好。
1 |
|
插入数据
MySQL 表中使用 INSERT INTO 语句来插入数据。
你可以通过 mysql> 命令提示窗口中向数据表中插入数据,或者通过PHP脚本来插入数据。
语法
以下为向MySQL数据表插入数据通用的 INSERT INTO SQL语法:
1 |
|
参数说明:
table_name
是你要插入数据的表的名称。column1
,column2
,column3
, … 是表中的列名。value1
,value2
,value3
, … 是要插入的具体数值。
如果数据是字符型,必须使用单引号 ’ 或者双引号 ",如: ‘value1’, “value1”。
一个简单的实例,插入了一行数据到名为 users 的表中:
1 |
|
username
: 用户名,字符串类型。email
: 邮箱地址,字符串类型。birthdate
: 用户生日, 日期类型。is_active
: 是否已激活,布尔类型。
如果你要插入所有列的数据,可以省略列名:
1 |
|
这里,NULL 是用于自增长列的占位符,表示系统将为 id 列生成一个唯一的值。
如果你要插入多行数据,可以在 VALUES 子句中指定多组数值:
1 |
|
以上代码将在 users 表中插入三行数据。
1 |
|
查询数据
MySQL 数据库使用 SELECT 语句来查询数据。
你可以通过 mysql> 命令提示窗口中在数据库中查询数据,或者通过 PHP 脚本来查询数据。
语法
以下为在 MySQL 数据库中查询数据通用的 SELECT 语法:
1 |
|
参数说明:
column1
,column2
, … 是你想要选择的列的名称,如果使用*
表示选择所有列。table_name
是你要从中查询数据的表的名称。WHERE condition
是一个可选的子句,用于指定过滤条件,只返回符合条件的行。ORDER BY column_name [ASC | DESC]
是一个可选的子句,用于指定结果集的排序顺序,默认是升序(ASC)。LIMIT number
是一个可选的子句,用于限制返回的行数。
1 |
|
SELECT 语句可以是灵活的,我们可以根据实际需求组合和使用这些子句,比如同时使用 WHERE 和 ORDER BY 子句,或者使用 LIMIT 控制返回的行数。
在 WHERE
子句中,你可以使用各种条件运算符(如 =
, <
, >
, <=
, >=
, !=
),逻辑运算符(如 AND
, OR
, NOT
),以及通配符(如 %
)等。
以下是一些进阶的 SELECT 语句实例:
1 |
|
WHERE 子句
我们知道从 MySQL 表中使用 SELECT 语句来读取数据。
如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句中。
WHERE 子句用于在 MySQL 中过滤查询结果,只返回满足特定条件的行。
语法
以下是 SQL SELECT 语句使用 WHERE 子句从数据表中读取数据的通用语法:
1 |
|
参数说明:
column1
,column2
, … 是你要选择的列的名称,如果使用*
表示选择所有列。table_name
是你要从中查询数据的表的名称。WHERE condition
是用于指定过滤条件的子句。
更多说明:
- 查询语句中你可以使用一个或者多个表,表之间使用逗号**,** 分割,并使用WHERE语句来设定查询条件。
- 你可以在 WHERE 子句中指定任何条件。
- 你可以使用 AND 或者 OR 指定一个或多个条件。
- WHERE 子句也可以运用于 SQL 的 DELETE 或者 UPDATE 命令。
- WHERE 子句类似于程序语言中的 if 条件,根据 MySQL 表中的字段值来读取指定的数据。
以下为操作符列表,可用于 WHERE 子句中。
下表中实例假定 A 为 10, B 为 20
操作符 | 描述 | 实例 |
---|---|---|
= | 等号,检测两个值是否相等,如果相等返回true | (A = B) 返回false。 |
<>, != | 不等于,检测两个值是否相等,如果不相等返回true | (A != B) 返回 true。 |
> | 大于号,检测左边的值是否大于右边的值, 如果左边的值大于右边的值返回true | (A > B) 返回false。 |
< | 小于号,检测左边的值是否小于右边的值, 如果左边的值小于右边的值返回true | (A < B) 返回 true。 |
>= | 大于等于号,检测左边的值是否大于或等于右边的值, 如果左边的值大于或等于右边的值返回true | (A >= B) 返回false。 |
<= | 小于等于号,检测左边的值是否小于或等于右边的值, 如果左边的值小于或等于右边的值返回true | (A <= B) 返回 true。 |
简单实例
- 等于条件:
1 |
|
- 不等于条件:
1 |
|
- 大于条件:
1 |
|
- 小于条件:
1 |
|
- 大于等于条件:
1 |
|
- 小于等于条件:
1 |
|
- 组合条件(AND、OR):
1 |
|
- 模糊匹配条件(LIKE):
1 |
|
- IN 条件:
1 |
|
- NOT 条件:
1 |
|
- BETWEEN 条件:
1 |
|
- IS NULL 条件
1 |
|
- IS NOT NULL 条件:
1 |
|
如果我们想在 MySQL 数据表中读取指定的数据,WHERE 子句是非常有用的。
使用主键来作为 WHERE 子句的条件查询是非常快速的。
如果给定的条件在表中没有任何匹配的记录,那么查询不会返回任何数据。
UPDATE 更新
如果我们需要修改或更新 MySQL 中的数据,我们可以使用 UPDATE 命令来操作。
语法
以下是 UPDATE 命令修改 MySQL 数据表数据的通用 SQL 语法:
1 |
|
参数说明:
table_name
是你要更新数据的表的名称。column1
,column2
, … 是你要更新的列的名称。value1
,value2
, … 是新的值,用于替换旧的值。WHERE condition
是一个可选的子句,用于指定更新的行。如果省略WHERE
子句,将更新表中的所有行。
更多说明:
- 你可以同时更新一个或多个字段。
- 你可以在 WHERE 子句中指定任何条件。
- 你可以在一个单独表中同时更新数据。
当你需要更新数据表中指定行的数据时 WHERE 子句是非常有用的。
实例
以下实例演示了如何使用 UPDATE 语句。
- 更新单个列的值:
1 |
|
- 更新多个列的值:
1 |
|
- 使用表达式更新值:
1 |
|
以上 SQL 语句将每个属于 ‘Electronics’ 类别的产品的价格都增加了 10%。
- 更新符合条件的所有行:
1 |
|
以上 SQL 语句将所有学生的状态更新为 ‘Graduated’。
- 更新使用子查询的值:
1 |
|
以上 SQL 语句通过子查询计算每个 ‘Premium’ 类型客户的总购买金额,并将该值更新到 total_purchases 列中。
注意: 在使用 UPDATE 语句时,请确保你提供了足够的条件来确保只有你想要更新的行被修改。如果不提供 WHERE 子句,将更新表中的所有行,可能导致不可预测的结果。
DELETE 语句
你可以使用 DELETE FROM 命令来删除 MySQL 数据表中的记录。
你可以在 mysql> 命令提示符或 PHP 脚本中执行该命令。
语法
以下是 DELETE 语句从 MySQL 数据表中删除数据的通用语法:
1 |
|
参数说明:
table_name
是你要删除数据的表的名称。WHERE condition
是一个可选的子句,用于指定删除的行。如果省略WHERE
子句,将删除表中的所有行。
更多说明:
- 如果没有指定 WHERE 子句,MySQL 表中的所有记录将被删除。
- 你可以在 WHERE 子句中指定任何条件
- 您可以在单个表中一次性删除记录。
当你想删除数据表中指定的记录时 WHERE 子句是非常有用的。
实例
以下实例演示了如何使用 DELETE 语句。
- 删除符合条件的行:
1 |
|
以上 SQL 语句删除了 students 表中所有 graduation_year 为 2021 的学生的记录。
- 删除所有行:
1 |
|
以上 SQL 语句删除了 orders 表中的所有记录,但表结构保持不变。
- 使用子查询删除符合条件的行:
1 |
|
以上 SQL 语句通过子查询删除了 orders 表中在 ‘2023-01-01’ 之前下的订单对应的客户。
注意: 在使用 DELETE 语句时,请确保你提供了足够的条件来确保只有你想要删除的行被删除。如果不提供 WHERE 子句,将删除表中的所有行,可能导致不可预测的结果。
LIKE 子句
我们知道在 MySQL 中使用 SELECT 命令来读取数据, 同时我们可以在 SELECT 语句中使用 WHERE 子句来获取指定的记录。
WHERE 子句中可以使用等号 = 来设定获取数据的条件,如 “runoob_author = ‘RUNOOB.COM’”。
但是有时候我们需要获取 runoob_author 字段含有 “COM” 字符的所有记录,这时我们就需要在 WHERE 子句中使用 LIKE 子句。
LIKE 子句是在 MySQL 中用于在 WHERE 子句中进行模糊匹配的关键字。它通常与通配符一起使用,用于搜索符合某种模式的字符串。
LIKE 子句中使用百分号 **%**字符来表示任意字符,类似于UNIX或正则表达式中的星号 *****。
如果没有使用百分号 %, LIKE 子句与等号 = 的效果是一样的。
语法
以下是 SQL SELECT 语句使用 LIKE 子句从数据表中读取数据的通用语法:
1 |
|
参数说明:
column1
,column2
, … 是你要选择的列的名称,如果使用*
表示选择所有列。table_name
是你要从中查询数据的表的名称。column_name
是你要应用LIKE
子句的列的名称。pattern
是用于匹配的模式,可以包含通配符。
更多说明:
- 你可以在 WHERE 子句中指定任何条件。
- 你可以在 WHERE 子句中使用LIKE子句。
- 你可以使用LIKE子句代替等号 =。
- LIKE 通常与 % 一同使用,类似于一个元字符的搜索。
- 你可以使用 AND 或者 OR 指定一个或多个条件。
- 你可以在 DELETE 或 UPDATE 命令中使用 WHERE…LIKE 子句来指定条件。
实例
以下是一些 LIKE 子句的使用实例。
- 百分号通配符 %:
% 通配符表示零个或多个字符。例如,‘a%’ 匹配以字母 ‘a’ 开头的任何字符串。
1 |
|
以上 SQL 语句将选择所有姓氏以 ‘S’ 开头的客户。
- 下划线通配符 _:
_ 通配符表示一个字符。例如,‘_r%’ 匹配第二个字母为 ‘r’ 的任何字符串。
1 |
|
以上 SQL 语句将选择产品名称的第二个字符为 ‘a’ 的所有产品。
- 组合使用 % 和 _:
1 |
|
以上 SQL 语句将匹配以字母 ‘a’ 开头,然后是零个或多个字符,接着是 ‘o’,最后是一个任意字符的字符串,如 ‘aaron’、‘apol’。
- 不区分大小写的匹配:
1 |
|
以上 SQL 语句将选择姓氏以 ‘smi’ 开头的所有员工,不区分大小写。
LIKE 子句提供了强大的模糊搜索能力,可以根据不同的模式和需求进行定制。在使用时,请确保理解通配符的含义,并根据实际情况进行匹配。
UNION 操作符
本教程为大家介绍 MySQL UNION 操作符的语法和实例。
描述
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合,并去除重复的行。
UNION 操作符必须由两个或多个 SELECT 语句组成,每个 SELECT 语句的列数和对应位置的数据类型必须相同。
语法
MySQL UNION 操作符语法格式:
1 |
|
参数说明:
column1
,column2
, … 是你要选择的列的名称,如果使用*
表示选择所有列。table1
,table2
, … 是你要从中查询数据的表的名称。condition1
,condition2
, … 是每个SELECT
语句的过滤条件,是可选的。ORDER BY
子句是一个可选的子句,用于指定合并后的结果集的排序顺序。
实例
- 基本的 UNION 操作:
1 |
|
以上 SQL 语句将选择客户表和供应商表中所有城市的唯一值,并按城市名称升序排序。
- 使用过滤条件的 UNION:
1 |
|
以上 SQL 语句将选择电子产品和服装类别的产品名称,并按产品名称升序排序。
- UNION 操作中的列数和数据类型必须相同:
1 |
|
以上 SQL 语句中,departments 表中的 department_name 列被映射到了 employees 表中的 last_name 列,但是列数和数据类型必须相同。
- 使用 UNION ALL 不去除重复行:
1 |
|
以上 SQL 语句使用 UNION ALL 将客户表和供应商表中的所有城市合并在一起,不去除重复行。
UNION 操作符在合并结果集时会去除重复行,而 UNION ALL 不会去除重复行,因此 UNION ALL 的性能可能更好,但如果你确实希望去除重复行,可以使用 UNION。
示例
演示数据库
在本教程中,我们将使用 RUNOOB 样本数据库。
下面是选自 “Websites” 表的数据:
1 |
|
下面是 “apps” APP 的数据:
1 |
|
UNION 实例
- 下面的 SQL 语句从 “Websites” 和 “apps” 表中选取所有不同的country(只有不同的值):
1 |
|
执行以上 SQL 输出结果如下:
**注释:**UNION 不能用于列出两个表中所有的country。如果一些网站和APP来自同一个国家,每个国家只会列出一次。UNION 只会选取不同的值。请使用 UNION ALL 来选取重复的值!
UNION ALL 实例
下面的 SQL 语句使用 UNION ALL 从 “Websites” 和 “apps” 表中选取所有的country(也有重复的值):
1 |
|
执行以上 SQL 输出结果如下:
带有 WHERE 的 SQL UNION ALL
下面的 SQL 语句使用 UNION ALL 从 “Websites” 和 “apps” 表中选取所有的中国(CN)的数据(也有重复的值):
1 |
|
执行以上 SQL 输出结果如下:
ORDER BY(排序) 语句
我们知道从 MySQL 表中使用 SELECT 语句来读取数据。
如果我们需要对读取的数据进行排序,我们就可以使用 MySQL 的 ORDER BY 子句来设定你想按哪个字段哪种方式来进行排序,再返回搜索结果。
MySQL ORDER BY(排序) 语句可以按照一个或多个列的值进行升序(ASC)或降序(DESC)排序。
语法
以下是 SELECT 语句使用 ORDER BY 子句将查询数据排序后再返回数据:
1 |
|
参数说明:
column1
,column2
, … 是你要选择的列的名称,如果使用*
表示选择所有列。table_name
是你要从中查询数据的表的名称。ORDER BY column1 [ASC | DESC], column2 [ASC | DESC], ...
是用于指定排序顺序的子句。ASC
表示升序(默认),DESC
表示降序。
更多说明:
- 你可以使用任何字段来作为排序的条件,从而返回排序后的查询结果。
- 你可以设定多个字段来排序。
- 你可以使用 ASC 或 DESC 关键字来设置查询结果是按升序或降序排列。 默认情况下,它是按升序排列。
- 你可以添加 WHERE…LIKE 子句来设置条件。
实例
以下是一些 ORDER BY 子句的使用实例。
- 单列排序:
1 |
|
以上 SQL 语句将选择产品表 products 中的所有产品,并按产品名称升序 ASC 排序。
- 多列排序:
1 |
|
以上 SQL 语句将选择员工表 employees 中的所有员工,并先按部门 ID 升序 ASC 排序,然后在相同部门中按雇佣日期降序 DESC 排序。
- 使用数字表示列的位置:
1 |
|
以上 SQL 语句将选择员工表 employees 中的名字和工资列,并按第三列(salary)降序 DESC 排序,然后按第一列(first_name)升序 ASC 排序。
- 使用表达式排序:
1 |
|
以上 SQL 语句将选择产品表 products 中的产品名称和根据折扣率计算的折扣后价格,并按折扣后价格降序 DESC 排序。
5.从 MySQL 8.0.16 版本开始,可以使用 NULLS FIRST 或 NULLS LAST 处理 NULL 值:
1 |
|
以上 SQL 语句将选择产品表 products 中的产品名称和价格,并按价格降序 DESC 排序,将 NULL 值排在最后。
相反,如果你想让 NULL 值排在前面,可以这样写:
1 |
|
ORDER BY 子句是一个强大的工具,可以根据不同的业务需求对查询结果进行排序。在实际应用中,注意选择适当的列和排序顺序,以获得符合期望的排序效果。
MySQL GROUP BY 语句
GROUP BY 语句根据一个或多个列对结果集进行分组。
在分组的列上我们可以使用 COUNT, SUM, AVG,等函数。
GROUP BY 语句是 SQL 查询中用于汇总和分析数据的重要工具,尤其在处理大量数据时,它能够提供有用的汇总信息。
GROUP BY 语法
1 |
|
column1
:指定分组的列。aggregate_function(column2)
:对分组后的每个组执行的聚合函数。table_name
:要查询的表名。condition
:可选,用于筛选结果的条件。
假设有一个名为 orders 的表,包含以下列:order_id、customer_id、order_date 和 order_amount。
我们想要按照 customer_id 进行分组,并计算每个客户的订单总金额,SQL 语句如下:
实例
1 |
|
以上实例中,我们使用 GROUP BY customer_id 将结果按 customer_id 列分组,然后使用 SUM(order_amount) 计算每个组中 order_amount 列的总和。
AS total_amount 是为了给计算结果取一个别名,使查询结果更易读。
注意事项:
GROUP BY
子句通常与聚合函数一起使用,因为分组后需要对每个组进行聚合操作。SELECT
子句中的列通常要么是分组列,要么是聚合函数的参数。- 可以使用多个列进行分组,只需在
GROUP BY
子句中用逗号分隔列名即可。
实例
1 |
|
连接的使用
在前几章节中,我们已经学会了如何在一张表中读取数据,这是相对简单的,但是在真正的应用中经常需要从多个数据表中读取数据。
本章节我们将向大家介绍如何使用 MySQL 的 JOIN 在两个或多个表中查询数据。
你可以在 SELECT, UPDATE 和 DELETE 语句中使用 MySQL 的 JOIN 来联合多表查询。
JOIN 按照功能大致分为如下三类:
- INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录。
- LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录。
- RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。
本章节使用的数据库结构及数据下载:runoob-mysql-join-test.sql。
INNER JOIN
INNER JOIN 返回两个表中满足连接条件的匹配行,以下是 INNER JOIN 语句的基本语法:
1 |
|
参数说明:
column1
,column2
, … 是你要选择的列的名称,如果使用*
表示选择所有列。table1
,table2
是要连接的两个表的名称。table1.column_name = table2.column_name
是连接条件,指定了两个表中用于匹配的列。
简单的 INNER JOIN:
1 |
|
以上 SQL 语句将选择 orders 表和 customers 表中满足连接条件的订单 ID 和客户名称。
- 使用表别名:
1 |
|
以上 SQL 语句使用表别名 o 和 c 作为 orders 和 customers 表的别名。
- 多表 INNER JOIN:
1 |
|
以上 SQL 语句涉及了 orders、customers、order_items 和 products 四个表的连接。它选择了订单 ID、客户名称和产品名称,连接了这些表的关联列。
- 使用 WHERE 子句进行过滤:
1 |
|
以上 SQL 语句在 INNER JOIN 后使用 WHERE 子句,过滤了订单日期在 ‘2023-01-01’ 及以后的订单。
LEFT JOIN
LEFT JOIN 返回左表的所有行,并包括右表中匹配的行,如果右表中没有匹配的行,将返回 NULL 值,以下是 LEFT JOIN 语句的基本语法:
1 |
|
- 简单的 LEFT JOIN:
1 |
|
以上 SQL 语句将选择客户表中的客户 ID 和客户名称,并包括左表 customers 中的所有行,以及匹配的订单 ID(如果有的话)。
- 使用表别名:
1 |
|
以上 SQL 语句使用表别名 c 和 o 分别代替 customers 和 orders 表的名称。
- 多表 LEFT JOIN:
1 |
|
以上 SQL 语句连接了 customers、orders、order_items 和 products 四个表,并选择了客户 ID、客户名称、订单 ID 和产品名称。左连接保证了即使在 order_items 或 products 中没有匹配的行,仍然会返回客户和订单的信息。
- 使用 WHERE 子句进行过滤:
1 |
|
以上 SQL 语句在 LEFT JOIN 后使用 WHERE 子句,过滤了订单日期在 ‘2023-01-01’ 及以后的订单,以及没有匹配订单的客户。
LEFT JOIN 是一种常用的连接类型,尤其在需要返回左表中所有行的情况下。当右表中没有匹配的行时,相关列将显示为 NULL。在使用 LEFT JOIN 时,请确保理解连接条件并根据需求过滤结果。
RIGHT JOIN
RIGHT JOIN 返回右表的所有行,并包括左表中匹配的行,如果左表中没有匹配的行,将返回 NULL 值,以下是 RIGHT JOIN 语句的基本语法::
1 |
|
以下是一个简单的 RIGHT JOIN 实例:
1 |
|
以上 SQL 语句将选择右表 orders 中的所有订单 ID,并包括左表 customers 中匹配的客户 ID。如果在 customers 表中没有匹配的客户 ID,相关列将显示为 NULL。
在开发过程中中,RIGHT JOIN 并不经常使用,因为它可以用 LEFT JOIN 和表的顺序交换来实现相同的效果。例如,上面的查询可以通过使用 LEFT JOIN 改写为:
1 |
|
以上 SQL 语句返回相同的结果,因为 LEFT JOIN 与 RIGHT JOIN 是对称的。在实际使用中,你可以根据个人偏好或组织规范选择使用哪种形式。
NULL 值处理
我们已经知道 MySQL 使用 SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作。
在 MySQL 中,NULL 用于表示缺失的或未知的数据,处理 NULL 值需要特别小心,因为在数据库中它可能会导致不同于预期的结果。
为了处理这种情况,MySQL提供了三大运算符:
- IS NULL: 当列的值是 NULL,此运算符返回 true。
- IS NOT NULL: 当列的值不为 NULL, 运算符返回 true。
- <=>: 比较操作符(不同于 = 运算符),当比较的的两个值相等或者都为 NULL 时返回 true。
关于 NULL 的条件比较运算是比较特殊的。你不能使用 = NULL 或 != NULL 在列中查找 NULL 值 。
在 MySQL 中,NULL 值与任何其它值的比较(即使是 NULL)永远返回 NULL,即 NULL = NULL 返回 NULL 。
MySQL 中处理 NULL 使用 IS NULL 和 IS NOT NULL 运算符。
注意:
1
select * , columnName1+ifnull(columnName2,0) from tableName;
columnName1,columnName2 为 int 型,当 columnName2 中,有值为 null 时,columnName1+columnName2=null, ifnull(columnName2,0) 把 columnName2 中 null 值转为 0。
MySQL 中处理 NULL 值的常见注意事项和技巧
- 检查是否为 NULL:
要检查某列是否为 NULL,可以使用 IS NULL 或 IS NOT NULL 条件。
1 |
|
- 使用 COALESCE 函数处理 NULL:
COALESCE 函数可以用于替换为 NULL 的值,它接受多个参数,返回参数列表中的第一个非 NULL 值:
1 |
|
以上 SQL 语句中,如果 stock_quantity 列为 NULL,则 COALESCE 将返回 0。
- 使用 IFNULL 函数处理 NULL:
IFNULL 函数是 COALESCE 的 MySQL 特定版本,它接受两个参数,如果第一个参数为 NULL,则返回第二个参数。
1 |
|
- NULL 排序:
在使用 ORDER BY 子句进行排序时,NULL 值默认会被放在排序的最后。如果希望将 NULL 值放在最前面,可以使用 ORDER BY column_name ASC NULLS FIRST,反之使用 ORDER BY column_name DESC NULLS LAST。
1 |
|
- 使用 <=> 操作符进行 NULL 比较:
<=> 操作符是 MySQL 中用于比较两个表达式是否相等的特殊操作符,对于 NULL 值的比较也会返回 TRUE。它可以用于处理 NULL 值的等值比较。
1 |
|
- 注意聚合函数对 NULL 的处理:
在使用聚合函数(如 COUNT, SUM, AVG)时,它们会忽略 NULL 值,因此可能会得到不同于预期的结果。如果希望将 NULL 视为 0,可以使用 COALESCE 或 IFNULL。
1 |
|
这样即使 salary 为 NULL,聚合函数也会将其视为 0。
处理 NULL 值时,要特别小心确保查询和操作的语义符合预期。在设计表结构时,也需要考虑 NULL 值的使用场景和合理性。
正则表达式
在前面的章节我们已经了解到 MySQL 可以通过 LIKE …% 来进行模糊匹配。
MySQL 同样也支持其他正则表达式的匹配, MySQL 中使用 REGEXP 和 RLIKE操作符来进行正则表达式匹配。
如果您了解 PHP 或 Perl,那么操作起来就非常简单,因为 MySQL 的正则表达式匹配与这些脚本的类似。
下表中的正则模式可应用于 REGEXP 操作符中。
模式 | 描述 |
---|---|
^ | 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。 |
. | 匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像 ‘[.\n]’ 的模式。 |
[…] | 字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。 |
[^…] | 负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’。 |
p1|p2|p3 | 匹配 p1 或 p2 或 p3。例如,‘z|food’ 能匹配 “z” 或 “food”。‘(z|f)ood’ 则匹配 “zood” 或 “food”。 |
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。 |
正则表达式匹配的字符类
.
:匹配任意单个字符。^
:匹配字符串的开始。$
:匹配字符串的结束。*
:匹配零个或多个前面的元素。+
:匹配一个或多个前面的元素。?
:匹配零个或一个前面的元素。[abc]
:匹配字符集中的任意一个字符。[^abc]
:匹配除了字符集中的任意一个字符以外的字符。[a-z]
:匹配范围内的任意一个小写字母。[0-9]
:匹配一个数字字符。\w
:匹配一个字母数字字符(包括下划线)。\s
:匹配一个空白字符。
使用 REGEXP 进行模式匹配
REGEXP 是用于进行正则表达式匹配的运算符。
REGEXP 用于检查一个字符串是否匹配指定的正则表达式模式,以下是 REGEXP 运算符的基本语法:
1 |
|
参数说明:
column1
,column2
, … 是你要选择的列的名称,如果使用*
表示选择所有列。table_name
是你要从中查询数据的表的名称。column_name
是你要进行正则表达式匹配的列的名称。'pattern'
是一个正则表达式模式。
查找 name 字段中以 ‘st’ 为开头的所有数据:
1 |
|
查找 name 字段中以 ‘ok’ 为结尾的所有数据:
1 |
|
查找 name 字段中包含 ‘mar’ 字符串的所有数据:
1 |
|
查找 name 字段中以元音字符开头或以 ‘ok’ 字符串结尾的所有数据:
1 |
|
选择订单表中描述中包含 “item” 后跟一个或多个数字的记录。
1 |
|
使用 BINARY 关键字,使得匹配区分大小写:
1 |
|
使用 OR 进行多个匹配条件,以下将选择姓氏为 “Smith” 或 “Johnson” 的员工记录:
1 |
|
使用 RLIKE 进行模式匹配
RLIKE 是 MySQL 中用于进行正则表达式匹配的运算符,与 REGEXP 是一样的,RLIKE 和 REGEXP 可以互换使用,没有区别。
以下是使用 RLIKE 进行正则表达式匹配的基本语法:
1 |
|
参数说明:
column1
,column2
, … 是你要选择的列的名称,如果使用*
表示选择所有列。table_name
是你要从中查询数据的表的名称。column_name
是你要进行正则表达式匹配的列的名称。'pattern'
是一个正则表达式模式。
1 |
|
以上 SQL 语句选择产品名称以数字开头的所有产品。
事务
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
在 MySQL 中,事务是一组SQL语句的执行,它们被视为一个单独的工作单元。
- 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
- 事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
- 事务用来管理 insert、update、delete 语句
一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
- 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
- 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
事务控制语句
- BEGIN 或 START TRANSACTION 显式地开启一个事务;
- COMMIT 也可以使用 COMMIT WORK,不过二者是等价的。COMMIT 会提交事务,并使已对数据库进行的所有修改成为永久性的;
- ROLLBACK 也可以使用 ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
- SAVEPOINT identifier,SAVEPOINT 允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT;
- RELEASE SAVEPOINT identifier 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
- ROLLBACK TO identifier 把事务回滚到标记点;
- SET TRANSACTION 用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。
MYSQL 事务处理主要有两种方法:
1、用 BEGIN, ROLLBACK, COMMIT 来实现
- BEGIN 或 START TRANSACTION:开用于开始一个事务。
- ROLLBACK 事务回滚,取消之前的更改。
- COMMIT:事务确认,提交事务,使更改永久生效。
2、直接用 SET 来改变 MySQL 的自动提交模式:
- SET AUTOCOMMIT=0 禁止自动提交
- SET AUTOCOMMIT=1 开启自动提交
BEGIN 或 START TRANSACTION – 用于开始一个事务:
1 |
|
COMMIT – 用于提交事务,将所有的修改永久保存到数据库:
1 |
|
ROLLBACK – 用于回滚事务,撤销自上次提交以来所做的所有更改:
1 |
|
SAVEPOINT – 用于在事务中设置保存点,以便稍后能够回滚到该点:
1 |
|
ROLLBACK TO SAVEPOINT – 用于回滚到之前设置的保存点:
1 |
|
下面是一个简单的 MySQL 事务的例子:
1 |
|
事务测试
1 |
|
ALTER 命令
当我们需要修改数据表名或者修改数据表字段时,就需要使用到 MySQL ALTER 命令。
MySQL 的 ALTER 命令用于修改数据库、表和索引等对象的结构。
ALTER 命令允许你添加、修改或删除数据库对象,并且可以用于更改表的列定义、添加约束、创建和删除索引等操作。
ALTER 命令非常强大,可以在数据库结构发生变化时进行灵活的修改和调整。
以下是 ALTER 命令的常见用法和实例:
- 添加列
1 |
|
以下 SQL 语句在 employees 表中添加了一个名为 birth_date 的日期列:
1 |
|
- 修改列的数据类型
1 |
|
以下 SQL 语句将 employees 表中的 salary 列的数据类型修改为 DECIMAL(10,2):
1 |
|
- 修改列名
1 |
|
以下 SQL 语句将 employees 表中的某个列的名字由 old_column_name 修改为 new_column_name,并且可以同时修改数据类型:
1 |
|
- 删除列
1 |
|
以下 SQL 语句将 employees 表中的 birth_date 列删除:
1 |
|
- 添加 PRIMARY KEY
1 |
|
以下 SQL 语句在 employees 表中添加了一个主键:
1 |
|
- 添加 FOREIGN KEY
1 |
|
以下 SQL 语句在 orders 表中添加了一个外键,关联到 customers 表的 customer_id 列:
1 |
|
- 修改表名
1 |
|
以下 SQL 语句将表名由 employees 修改为 staff:
1 |
|
**注意:**在使用 ALTER 命令时要格外小心,因为一些操作可能需要重建表或索引,这可能会影响数据库的性能和运行时间。
在进行重要的结构修改时,建议先备份数据,并在生产环境中谨慎操作。
索引
MySQL 索引是一种数据结构,用于加快数据库查询的速度和性能。
MySQL 索引的建立对于 MySQL 的高效运行是很重要的,索引可以大大提高 MySQL 的检索速度。
MySQL 索引类似于书籍的索引,通过存储指向数据行的指针,可以快速定位和访问表中的特定数据。
打个比方,如果合理的设计且使用索引的 MySQL 是一辆兰博基尼的话,那么没有设计和使用索引的 MySQL 就是一个人力三轮车。
拿汉语字典的目录页(索引)打比方,我们可以按拼音、笔画、偏旁部首等排序的目录(索引)快速查找到需要的字。
索引分单列索引和组合索引:
- 单列索引,即一个索引只包含单个列,一个表可以有多个单列索引。
- 组合索引,即一个索引包含多个列。
创建索引时,你需要确保该索引是应用在 SQL 查询语句的条件(一般作为 WHERE 子句的条件)。
实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。
索引虽然能够提高查询性能,但也需要注意以下几点:
- 索引需要占用额外的存储空间。
- 对表进行插入、更新和删除操作时,索引需要维护,可能会影响性能。
- 过多或不合理的索引可能会导致性能下降,因此需要谨慎选择和规划索引。
普通索引
索引能够显著提高查询的速度,尤其是在大型表中进行搜索时。通过使用索引,MySQL 可以直接定位到满足查询条件的数据行,而无需逐行扫描整个表。
创建索引
使用 CREATE INDEX 语句可以创建普通索引。
普通索引是最常见的索引类型,用于加速对表中数据的查询。
CREATE INDEX 的语法:
1 |
|
CREATE INDEX
: 用于创建普通索引的关键字。index_name
: 指定要创建的索引的名称。索引名称在表中必须是唯一的。table_name
: 指定要在哪个表上创建索引。(column1, column2, ...)
: 指定要索引的表列名。你可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。ASC
和DESC
(可选): 用于指定索引的排序顺序。默认情况下,索引以升序(ASC)排序。
以下实例假设我们有一个名为 students 的表,包含 id、name 和 age 列,我们将在 name 列上创建一个普通索引。
1 |
|
上述语句将在 students 表的 name 列上创建一个名为 idx_name 的普通索引,这将有助于提高通过姓名进行搜索的查询性能。
需要注意的是,如果表中的数据量较大,索引的创建可能会花费一些时间,但一旦创建完成,查询性能将会显著提高。
修改表结构(添加索引)
我们可以使用 ALTER TABLE 命令可以在已有的表中创建索引。
ALTER TABLE 允许你修改表的结构,包括添加、修改或删除索引。
ALTER TABLE 创建索引的语法:
1 |
|
ALTER TABLE
: 用于修改表结构的关键字。table_name
: 指定要修改的表的名称。ADD INDEX
: 添加索引的子句。ADD INDEX
用于创建普通索引。index_name
: 指定要创建的索引的名称。索引名称在表中必须是唯一的。(column1, column2, ...)
: 指定要索引的表列名。你可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。ASC
和DESC
(可选): 用于指定索引的排序顺序。默认情况下,索引以升序(ASC)排序。
下面是一个实例,我们将在已存在的名为 employees 的表上创建一个普通索引:
1 |
|
上述语句将在 employees 表的 age 列上创建一个名为 idx_age 的普通索引。
创建表的时候直接指定
我们可以在创建表的时候,你可以在 CREATE TABLE 语句中直接指定索引,以创建表和索引的组合。
1 |
|
CREATE TABLE
: 用于创建新表的关键字。table_name
: 指定要创建的表的名称。(column1 data_type, column2 data_type, ...)
: 定义表的列名和数据类型。你可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。INDEX
: 用于创建普通索引的关键字。index_name
: 指定要创建的索引的名称。索引名称在表中必须是唯一的。(column1, column2, ...)
: 指定要索引的表列名。你可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。ASC
和DESC
(可选): 用于指定索引的排序顺序。默认情况下,索引以升序(ASC)排序。
下面是一个实例,我们要创建一个名为 students 的表,并在 age 列上创建一个普通索引。
1 |
|
在上述实例中,我们在 students 表的 age 列上创建了一个名为 idx_age 的普通索引。
删除索引的语法
我们可以使用 DROP INDEX 语句来删除索引。
DROP INDEX 的语法:
1 |
|
DROP INDEX
: 用于删除索引的关键字。index_name
: 指定要删除的索引的名称。ON table_name
: 指定要在哪个表上删除索引。
使用 ALTER TABLE 语句删除索引的语法如下:
1 |
|
ALTER TABLE
: 用于修改表结构的关键字。table_name
: 指定要修改的表的名称。DROP INDEX
: 用于删除索引的子句。index_name
: 指定要删除的索引的名称。
以下实例假设我们有一个名为 employees 的表,并在 age 列上有一个名为 idx_age 的索引,现在我们要删除这个索引:
1 |
|
或使用 ALTER TABLE 语句:
1 |
|
这两个命令都会从 employees 表中删除名为 idx_age 的索引。
如果该索引不存在,执行命令时会产生错误。因此,在删除索引之前最好确认该索引是否存在,或者使用错误处理机制来处理可能的错误情况。
唯一索引
在 MySQL 中,你可以使用 CREATE UNIQUE INDEX 语句来创建唯一索引。
唯一索引确保索引中的值是唯一的,不允许有重复值。
创建索引
1 |
|
CREATE UNIQUE INDEX
: 用于创建唯一索引的关键字组合。index_name
: 指定要创建的唯一索引的名称。索引名称在表中必须是唯一的。table_name
: 指定要在哪个表上创建唯一索引。(column1, column2, ...)
: 指定要索引的表列名。你可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。ASC
和DESC
(可选): 用于指定索引的排序顺序。默认情况下,索引以升序(ASC)排序。
以下是一个创建唯一索引的实例: 假设我们有一个名为 employees的 表,包含 id 和 email 列,现在我们想在email列上创建一个唯一索引,以确保每个员工的电子邮件地址都是唯一的。
1 |
|
以上实例将在 employees 表的 email 列上创建一个名为 idx_email 的唯一索引。
修改表结构添加索引
我们可以使用 ALTER TABLE 命令来创建唯一索引。
ALTER TABLE命令允许你修改已经存在的表结构,包括添加新的索引。
1 |
|
ALTER TABLE
: 用于修改表结构的关键字。table_name
: 指定要修改的表的名称。ADD CONSTRAINT
: 这是用于添加约束(包括唯一索引)的关键字。unique_constraint_name
: 指定要创建的唯一索引的名称,约束名称在表中必须是唯一的。UNIQUE (column1, column2, ...)
: 指定要索引的表列名。你可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。
以下是一个使用 ALTER TABLE 命令创建唯一索引的实例:假设我们有一个名为 employees 的表,包含 id 和 email 列,现在我们想在 email 列上创建一个唯一索引,以确保每个员工的电子邮件地址都是唯一的。
1 |
|
以上实例将在 employees 表的 email 列上创建一个名为 idx_email 的唯一索引。
请注意,如果表中已经有重复的 email 值,那么添加唯一索引将会失败。在创建唯一索引之前,你可能需要确保表中的 email 列没有重复的值。
创建表的时候直接指定
我们也可以在创建表的同时,你可以在 CREATE TABLE 语句中使用 UNIQUE 关键字来创建唯一索引。
这将在表创建时同时定义唯一索引约束。
CREATE TABLE 语句中创建唯一索引的语法:
1 |
|
CREATE TABLE
: 用于创建新表的关键字。table_name
: 指定要创建的表的名称。(column1 data_type, column2 data_type, ...)
: 定义表的列名和数据类型。你可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。CONSTRAINT
: 用于添加约束的关键字。index_name
: 指定要创建的唯一索引的名称。约束名称在表中必须是唯一的。UNIQUE (column1, column2, ...)
: 指定要索引的表列名。ASC
和DESC
(可选): 用于指定索引的排序顺序。默认情况下,索引以升序(ASC)排序。
以下是一个在创建表时创建唯一索引的实例:假设我们要创建一个名为 employees 的表,其中包含 id、name 和 email 列,我们希望 email 列的值是唯一的,因此我们要在创建表时定义唯一索引。
1 |
|
在这个例子中,email 列被定义为唯一索引,因为在它的后面加上了 UNIQUE 关键字。
请注意,使用 UNIQUE 关键字后,索引名称将自动生成,你也可以根据需要指定索引名称。
使用ALTER 命令添加和删除索引
有四种方式来添加数据表的索引:
-
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list):
该语句添加一个主键,主键列中的值必须唯一,主键的列的列表,可以是一个或多个列,不能包含 NULL 值。 。
-
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
-
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。
-
**ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list)😗*该语句指定了索引为 FULLTEXT ,用于全文索引。
以下实例为在表中添加索引。
1 |
|
你还可以在 ALTER 命令中使用 DROP 子句来删除索引。尝试以下实例删除索引:
1 |
|
使用 ALTER 命令添加和删除主键
主键作用于列上(可以一个列或多个列联合主键),添加主键时,你需要确保该主键默认不为空(NOT NULL)。实例如下:
1 |
|
你也可以使用 ALTER 命令删除主键:
1 |
|
删除主键时只需指定 PRIMARY KEY,但在删除索引时,你必须知道索引名。
显示索引信息
你可以使用 SHOW INDEX 命令来列出表中的相关的索引信息。
可以通过添加 \G 来格式化输出信息。
SHOW INDEX 语句::
1 |
|
SHOW INDEX
: 用于显示索引信息的关键字。FROM table_name
: 指定要查看索引信息的表的名称。\G
: 格式化输出信息。
执行上述命令后,将会显示指定表中所有索引的详细信息,包括索引名称(Key_name)、索引列(Column_name)、是否是唯一索引(Non_unique)、排序方式(Collation)、索引的基数(Cardinality)等。
临时表
MySQL 临时表在我们需要保存一些临时数据时是非常有用的。
临时表只在当前连接可见,当关闭连接时,MySQL 会自动删除表并释放所有空间。
在 MySQL 中,临时表是一种在当前会话中存在的表,它在会话结束时会自动被销毁。
MySQL 临时表只在当前连接可见,如果你使用PHP脚本来创建 MySQL 临时表,那每当 PHP 脚本执行完成后,该临时表也会自动销毁。
如果你使用了其他 MySQL 客户端程序连接 MySQL 数据库服务器来创建临时表,那么只有在关闭客户端程序时才会销毁临时表,当然你也可以手动销毁。
创建临时表
1 |
|
或者简写为:
1 |
|
插入数据到临时表
1 |
|
查询临时表
1 |
|
修改临时表
临时表的修改操作与普通表类似,可以使用 ALTER TABLE 命令。
1 |
|
删除临时表
临时表在会话结束时会自动被销毁,但你也可以使用 DROP TABLE 明确删除它。
1 |
|
实例
1 |
|
复制表
如果我们需要完全的复制 MySQL 的数据表,包括表的结构,索引,默认值等。
如果仅仅使用 CREATE TABLE … SELECT 命令,是无法实现的。
本章节将为大家介绍如何完整的复制 MySQL 数据表,步骤如下:
- 使用 SHOW CREATE TABLE 命令获取创建数据表(CREATE TABLE) 语句,该语句包含了原数据表的结构,索引等。
- 复制以下命令显示的 SQL 语句,修改数据表名,并执行SQL语句,通过以上命令 将完全的复制数据表结构。
- 如果你想复制表的内容,你就可以使用 INSERT INTO … SELECT 语句来实现。
实例
尝试以下实例来复制表 runoob_tbl 。
步骤一:
获取数据表的完整结构。
1 |
|
步骤二:
修改 SQL 语句的数据表名,并执行 SQL 语句。
1 |
|
步骤三:
执行完第二步骤后,你将在数据库中创建新的克隆表 clone_tbl。 如果你想拷贝数据表的数据你可以使用 INSERT INTO… SELECT 语句来实现。
1 |
|
执行以上步骤后,会完整的复制表的内容,包括表结构及表数据。
元数据
MySQL 元数据是关于数据库和其对象(如表、列、索引等)的信息。
元数据存储在系统表中,这些表位于 MySQL 数据库的 information_schema 数据库中,通过查询这些系统表,你可以获取关于数据库结构、对象和其他相关信息的详细信息。
你可能想知道MySQL以下三种信息:
- 查询结果信息: SELECT, UPDATE 或 DELETE语句影响的记录数。
- 数据库和数据表的信息: 包含了数据库及数据表的结构信息。
- MySQL 服务器信息: 包含了数据库服务器的当前状态,版本号等。
在 MySQL 的命令提示符中,我们可以很容易的获取以上服务器信息,但如果使用 Perl 或 PHP 等脚本语言,你就需要调用特定的接口函数来获取,接下来我们会详细介绍。
以下是一些常用的 MySQL 元数据查询:
查看所有数据库:
1 |
|
选择数据库:
1 |
|
查看数据库中的所有表:
1 |
|
查看表的结构:
1 |
|
查看表的索引:
1 |
|
查看表的创建语句:
1 |
|
查看表的行数:
1 |
|
查看列的信息:
1 |
|
以上SQL 语句中的 ‘your_database_name’ 和 ‘your_table_name’ 分别是你的数据库名和表名。
查看外键信息:
1 |
|
请替换上述 SQL 语句中的 ‘your_database_name’ 和 ‘your_table_name’ 为实际的数据库名和表名。
information_schema 数据库
information_schema 是 MySQL 数据库中的一个系统数据库,它包含有关数据库服务器的元数据信息,这些信息以表的形式存储在 information_schema 数据库中。
- SCHEMATA 表
存储有关数据库的信息,如数据库名、字符集、排序规则等。
1 |
|
- TABLES 表
包含有关数据库中所有表的信息,如表名、数据库名、引擎、行数等。
1 |
|
- COLUMNS 表
包含有关表中列的信息,如列名、数据类型、是否允许 NULL 等。
1 |
|
- STATISTICS 表
提供有关表索引的统计信息,如索引名、列名、唯一性等。
1 |
|
- KEY_COLUMN_USAGE 表
包含有关表中外键的信息,如外键名、列名、关联表等。
1 |
|
- REFERENTIAL_CONSTRAINTS 表
存储有关外键约束的信息,如约束名、关联表等。
1 |
|
这些表提供了丰富的元数据信息,可以用于查询数据库结构、表信息、列信息、索引信息等。
请注意,你需要将查询中的 ‘your_database_name’ 和 ‘your_table_name’ 替换为实际的数据库名和表名。
获取查询语句影响的记录数
PERL 实例
在 DBI 脚本中, 语句影响的记录数通过函数 do( ) 或 execute( )返回:
1 |
|
序列使用(AUTO_INCREMENT)
在 MySQL 中,序列是一种自增生成数字序列的对象,是一组整数 1、2、3、…,由于一张数据表只能有一个字段自增主键。
尽管 MySQL 本身并没有内建的序列类型,但可以使用 AUTO_INCREMENT 属性来模拟序列的行为,通常 AUTO_INCREMENT 属性用于指定表中某一列的自增性。
一个使用 AUTO_INCREMENT 创建表的例子:
1 |
|
以上例子中,id 列被定义为 INT AUTO_INCREMENT,这表示每次插入一行数据时,id 列的值会自动增加。主键约束保证了 id 列的唯一性。
当你插入一行数据时,可以不指定 id 列的值,数据库会自动为其分配一个唯一的、自增的值:
1 |
|
你也可以使用 LAST_INSERT_ID() 函数来获取刚刚插入的行的自增值:
1 |
|
如果你需要获取表的当前自增值,可以使用以下语句:
1 |
|
在结果集中,Auto_increment 列的值即为当前表的自增值。
请注意,使用 AUTO_INCREMENT 属性的列只能是整数类型(通常是 INT 或 BIGINT)。此外,如果你删除表中的某一行,其自增值不会被重新使用,而是会继续递增。如果你希望手动设置自增值,可以使用 SET 语句,但这不是一种常规的做法,因为可能引起唯一性冲突。
- 使用 AUTO_INCREMENT
MySQL 中最简单使用序列的方法就是使用 MySQL AUTO_INCREMENT 来定义序列。
实例
以下实例中创建了数据表 insect, insect 表中 id 无需指定值可实现自动增长。
1 |
|
- 获取 AUTO_INCREMENT 值
在 MySQL 的客户端中你可以使用 SQL 中的 LAST_INSERT_ID() 函数来获取最后的插入表中的自增列的值。
在 PHP 或 PERL 脚本中也提供了相应的函数来获取最后的插入表中的自增列的值。
处理重复数据
有些 MySQL 数据表中可能存在重复的记录,有些情况我们允许重复数据的存在,但有时候我们也需要删除这些重复的数据。
本章节我们将为大家介绍如何防止数据表出现重复数据及如何删除数据表中的重复数据。
- 防止表中出现重复数据
你可以在 MySQL 数据表中设置指定的字段为 PRIMARY KEY(主键) 或者 UNIQUE(唯一) 索引来保证数据的唯一性。
让我们尝试一个实例:下表中无索引及主键,所以该表允许出现多条重复记录。
1 |
|
如果你想设置表中字段 first_name,last_name 数据不能重复,你可以设置双主键模式来设置数据的唯一性, 如果你设置了双主键,那么那个键的默认值不能为 NULL,可设置为 NOT NULL。如下所示:
1 |
|
如果我们设置了唯一索引,那么在插入重复数据时,SQL 语句将无法执行成功,并抛出错。
INSERT IGNORE INTO 与 INSERT INTO 的区别就是 INSERT IGNORE INTO 会忽略数据库中已经存在的数据,如果数据库没有数据,就插入新的数据,如果有数据的话就跳过这条数据。这样就可以保留数据库中已经存在数据,达到在间隙中插入数据的目的。
以下实例使用了 INSERT IGNORE INTO,执行后不会出错,也不会向数据表中插入重复数据:
1 |
|
INSERT IGNORE INTO 当插入数据时,在设置了记录的唯一性后,如果插入重复数据,将不返回错误,只以警告形式返回。 而 REPLACE INTO 如果存在 primary 或 unique 相同的记录,则先删除掉。再插入新记录。
另一种设置数据的唯一性方法是添加一个 UNIQUE 索引,如下所示:
1 |
|
- 统计重复数据
以下我们将统计表中 first_name 和 last_name的重复记录数:
1 |
|
以上查询语句将返回 person_tbl 表中重复的记录数。 一般情况下,查询重复的值,请执行以下操作:
- 确定哪一列包含的值可能会重复。
- 在列选择列表使用COUNT(*)列出的那些列。
- 在GROUP BY子句中列出的列。
- HAVING子句设置重复数大于1。
- 过滤重复数据
如果你需要读取不重复的数据可以在 SELECT 语句中使用 DISTINCT 关键字来过滤重复数据。
1 |
|
你也可以使用 GROUP BY 来读取数据表中不重复的数据:
1 |
|
- 删除重复数据
如果你想删除数据表中的重复数据,你可以使用以下的SQL语句:
1 |
|
当然你也可以在数据表中添加 INDEX(索引) 和 PRIMAY KEY(主键)这种简单的方法来删除表中的重复记录。方法如下:
1 |
|
导出数据
mysqldump 命令可以用于备份和还原 MySQL 数据库。
如果你只想复制一张表,你可以使用 mysqldump 导出该表的结构和数据,然后再导入到新的数据库或新的表中。
以下是一个简单的实例。
备份表数据:
1 |
|
这将导出名为 old_table 的表的结构和数据到一个名为 old_table_dump.sql 的 SQL 文件。
你需要提供 MySQL 用户名和密码,并替换 username、dbname 和 old_table 为实际的值。
还原到新的数据库:
1 |
|
这将在新的数据库(new_dbname)中创建一个名为 old_table 的表,并将之前导出的结构和数据导入到新表中。
mysqldump 是 MySQL 提供的用于备份和导出数据库的命令行工具。
mysqldump 是 mysql 用于转存储数据库的实用程序。它主要产生一个 SQL 脚本,其中包含从头重新创建数据库所必需的命令 CREATE TABLE INSERT 等。
使用 mysqldump 导出数据需要使用 –tab 选项来指定导出文件指定的目录,该目标必须是可写的。
mysqldump 基本的用法:
1 |
|
参数说明:
-u
: 指定 MySQL 用户名。-p
: 提示输入密码。-h
: 指定 MySQL 主机名。database_name
: 要导出的数据库名称。output_file.sql
: 导出数据保存到的文件。
以下实例将数据表 runoob_tbl 导出到 /tmp 目录中:
1 |
|
- mysqldump 实例
1. 导出整个数据库
导出 mydatabase 数据库到 mydatabase_backup.sql 文件:
1 |
|
2. 导出特定表
如果你只想导出数据库中的某个表,可以使用以下命令:
1 |
|
或:
1 |
|
3. 导出数据库结构
如果只想导出数据库结构而不包括数据,可以使用 –no-data 选项:
1 |
|
4. 导出压缩文件
你可以将导出的数据进行压缩,以减小文件大小。例如,使用 gzip:
1 |
|
- 导出 SQL 格式的数据
导出 SQL 格式的数据到指定文件,如下所示:
1 |
|
以上命令创建的文件内容如下:
1 |
|
如果你需要导出整个数据库的数据,可以使用以下命令:
1 |
|
如果需要备份所有数据库,可以使用以下命令:
1 |
|
–all-databases 选项在 MySQL 3.23.12 及以后版本加入。
该方法可用于实现数据库的备份策略。
- 将数据表及数据库拷贝至其他主机
如果你需要将数据拷贝至其他的 MySQL 服务器上, 你可以在 mysqldump 命令中指定数据库名及数据表。
在源主机上执行以下命令,将数据备份至 dump.txt 文件中:
1 |
|
如果完整备份数据库,则无需使用特定的表名称。
如果你需要将备份的数据库导入到MySQL服务器中,可以使用以下命令,使用以下命令你需要确认数据库已经创建:
1 |
|
你也可以使用以下命令将导出的数据直接导入到远程的服务器上,但请确保两台服务器是相通的,是可以相互访问的:
1 |
|
以上命令中使用了管道来将导出的数据导入到指定的远程主机上。
导入数据
本章节我们为大家介绍几种简单的 MySQL 导入数据命令。
mysql -u your_username -p -h your_host -P your_port -D your_database
- mysql 命令导入
使用 mysql 命令导入语法格式为:
1 |
|
your_username、your_host、your_port、your_database 分别为你的 MySQL 用户名、主机、端口和数据库。
实例:
1 |
|
以上命令将将备份的整个数据库 runoob.sql 导入。
执行上述命令后,系统将要求输入 MySQL 用户的密码。输入密码并按Enter键。
这样,MySQL 将执行 SQL 文件中的语句,将数据导入到指定的数据库中。
请注意,如果 SQL 文件包含创建数据库的语句,确保在执行导入之前数据库已经存在。如果文件包含创建表的语句,确保表不存在或者是空的,以免导入数据时发生冲突。
- source 命令导入
source 命令导入数据库需要先登录到数库终端:
1 |
|
使用 source 命令的好处是,你可以在 MySQL 命令行中直接执行,而无需退出 MySQL 并使用其他命令。
- 使用 LOAD DATA 导入数据
MySQL 中提供了LOAD DATA INFILE语句来插入数据。 以下实例中将从当前目录中读取文件 dump.txt ,将该文件中的数据插入到当前数据库的 mytbl 表中。
1 |
|
如果指定LOCAL关键词,则表明从客户主机上按路径读取文件。如果没有指定,则文件在服务器上按路径读取文件。
你能明确地在LOAD DATA语句中指出列值的分隔符和行尾标记,但是默认标记是定位符和换行符。
两个命令的 FIELDS 和 LINES 子句的语法是一样的。两个子句都是可选的,但是如果两个同时被指定,FIELDS 子句必须出现在 LINES 子句之前。
如果用户指定一个 FIELDS 子句,它的子句 (TERMINATED BY、[OPTIONALLY] ENCLOSED BY 和 ESCAPED BY) 也是可选的,不过,用户必须至少指定它们中的一个。
1 |
|
LOAD DATA 默认情况下是按照数据文件中列的顺序插入数据的,如果数据文件中的列与插入表中的列不一致,则需要指定列的顺序。
如,在数据文件中的列顺序是 a,b,c,但在插入表的列顺序为b,c,a,则数据导入语法如下:
1 |
|
- 使用 mysqlimport 导入数据
mysqlimport 客户端提供了 LOAD DATA INFILEQL 语句的一个命令行接口。mysqlimport 的大多数选项直接对应 LOAD DATA INFILE 子句。
从文件 dump.txt 中将数据导入到 mytbl 数据表中, 可以使用以下命令:
1 |
|
mysqlimport 命令可以指定选项来设置指定格式,命令语句格式如下:
1 |
|
mysqlimport 语句中使用 --columns 选项来设置列的顺序:
1 |
|
- mysqlimport的常用选项介绍
选项 | 功能 |
---|---|
-d or --delete | 新数据导入数据表中之前删除数据数据表中的所有信息 |
-f or --force | 不管是否遇到错误,mysqlimport将强制继续插入数据 |
-i or --ignore | mysqlimport跳过或者忽略那些有相同唯一 关键字的行, 导入文件中的数据将被忽略。 |
-l or -lock-tables | 数据被插入之前锁住表,这样就防止了, 你在更新数据库时,用户的查询和更新受到影响。 |
-r or -replace | 这个选项与-i选项的作用相反;此选项将替代 表中有相同唯一关键字的记录。 |
–fields-enclosed- by= char | 指定文本文件中数据的记录时以什么括起的, 很多情况下 数据以双引号括起。 默认的情况下数据是没有被字符括起的。 |
–fields-terminated- by=char | 指定各个数据的值之间的分隔符,在句号分隔的文件中, 分隔符是句号。您可以用此选项指定数据之间的分隔符。 默认的分隔符是跳格符(Tab) |
–lines-terminated- by=str | 此选项指定文本文件中行与行之间数据的分隔字符串 或者字符。 默认的情况下mysqlimport以newline为行分隔符。 您可以选择用一个字符串来替代一个单个的字符: 一个新行或者一个回车。 |
mysqlimport 命令常用的选项还有 -v 显示版本(version), -p 提示输入密码(password)等。
函数
MySQL 有很多内置的函数,以下列出了这些函数的说明。
MySQL 字符串函数
函数 | 描述 | 实例 |
---|---|---|
ASCII(s) | 返回字符串 s 的第一个字符的 ASCII 码。 | 返回 CustomerName 字段第一个字母的 ASCII 码:SELECT ASCII(CustomerName) AS NumCodeOfFirstChar FROM Customers; |
CHAR_LENGTH(s) | 返回字符串 s 的字符数 | 返回字符串 RUNOOB 的字符数SELECT CHAR_LENGTH("RUNOOB") AS LengthOfString; |
CHARACTER_LENGTH(s) | 返回字符串 s 的字符数,等同于 CHAR_LENGTH(s) | 返回字符串 RUNOOB 的字符数SELECT CHARACTER_LENGTH("RUNOOB") AS LengthOfString; |
CONCAT(s1,s2…sn) | 字符串 s1,s2 等多个字符串合并为一个字符串 | 合并多个字符串SELECT CONCAT("SQL ", "Runoob ", "Gooogle ", "Facebook") AS ConcatenatedString; |
CONCAT_WS(x, s1,s2…sn) | 同 CONCAT(s1,s2,…) 函数,但是每个字符串之间要加上 x,x 可以是分隔符 | 合并多个字符串,并添加分隔符:SELECT CONCAT_WS("-", "SQL", "Tutorial", "is", "fun!")AS ConcatenatedString; |
FIELD(s,s1,s2…) | 返回第一个字符串 s 在字符串列表(s1,s2…)中的位置 | 返回字符串 c 在列表值中的位置:SELECT FIELD("c", "a", "b", "c", "d", "e"); |
FIND_IN_SET(s1,s2) | 返回在字符串s2中与s1匹配的字符串的位置 | 返回字符串 c 在指定字符串中的位置:SELECT FIND_IN_SET("c", "a,b,c,d,e"); |
FORMAT(x,n) | 函数可以将数字 x 进行格式化 “#,###.##”, 将 x 保留到小数点后 n 位,最后一位四舍五入。 | 格式化数字 “#,###.##” 形式:SELECT FORMAT(250500.5634, 2); -- 输出 250,500.56 |
INSERT(s1,x,len,s2) | 字符串 s2 替换 s1 的 x 位置开始长度为 len 的字符串 | 从字符串第一个位置开始的 6 个字符替换为 runoob:SELECT INSERT("google.com", 1, 6, "runoob"); -- 输出:runoob.com |
LOCATE(s1,s) | 从字符串 s 中获取 s1 的开始位置 | 获取 b 在字符串 abc 中的位置:SELECT LOCATE('st','myteststring'); -- 5 返回字符串 abc 中 b 的位置:SELECT LOCATE('b', 'abc') -- 2 |
LCASE(s) | 将字符串 s 的所有字母变成小写字母 | 字符串 RUNOOB 转换为小写:SELECT LCASE('RUNOOB') -- runoob |
LEFT(s,n) | 返回字符串 s 的前 n 个字符 | 返回字符串 runoob 中的前两个字符:SELECT LEFT('runoob',2) -- ru |
LOWER(s) | 将字符串 s 的所有字母变成小写字母 | 字符串 RUNOOB 转换为小写:SELECT LOWER('RUNOOB') -- runoob |
LPAD(s1,len,s2) | 在字符串 s1 的开始处填充字符串 s2,使字符串长度达到 len | 将字符串 xx 填充到 abc 字符串的开始处:SELECT LPAD('abc',5,'xx') -- xxabc |
LTRIM(s) | 去掉字符串 s 开始处的空格 | 去掉字符串 RUNOOB开始处的空格:SELECT LTRIM(" RUNOOB") AS LeftTrimmedString;-- RUNOOB |
MID(s,n,len) | 从字符串 s 的 n 位置截取长度为 len 的子字符串,同 SUBSTRING(s,n,len) | 从字符串 RUNOOB 中的第 2 个位置截取 3个 字符:SELECT MID("RUNOOB", 2, 3) AS ExtractString; -- UNO |
POSITION(s1 IN s) | 从字符串 s 中获取 s1 的开始位置 | 返回字符串 abc 中 b 的位置:SELECT POSITION('b' in 'abc') -- 2 |
REPEAT(s,n) | 将字符串 s 重复 n 次 | 将字符串 runoob 重复三次:SELECT REPEAT('runoob',3) -- runoobrunoobrunoob |
REPLACE(s,s1,s2) | 将字符串 s2 替代字符串 s 中的字符串 s1 | 将字符串 abc 中的字符 a 替换为字符 x:SELECT REPLACE('abc','a','x') --xbc |
REVERSE(s) | 将字符串s的顺序反过来 | 将字符串 abc 的顺序反过来:SELECT REVERSE('abc') -- cba |
RIGHT(s,n) | 返回字符串 s 的后 n 个字符 | 返回字符串 runoob 的后两个字符:SELECT RIGHT('runoob',2) -- ob |
RPAD(s1,len,s2) | 在字符串 s1 的结尾处添加字符串 s2,使字符串的长度达到 len | 将字符串 xx 填充到 abc 字符串的结尾处:SELECT RPAD('abc',5,'xx') -- abcxx |
RTRIM(s) | 去掉字符串 s 结尾处的空格 | 去掉字符串 RUNOOB 的末尾空格:SELECT RTRIM("RUNOOB ") AS RightTrimmedString; -- RUNOOB |
SPACE(n) | 返回 n 个空格 | 返回 10 个空格:SELECT SPACE(10); |
STRCMP(s1,s2) | 比较字符串 s1 和 s2,如果 s1 与 s2 相等返回 0 ,如果 s1>s2 返回 1,如果 s1<s2 返回 -1 | 比较字符串:SELECT STRCMP("runoob", "runoob"); -- 0 |
SUBSTR(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串 | 从字符串 RUNOOB 中的第 2 个位置截取 3个 字符:SELECT SUBSTR("RUNOOB", 2, 3) AS ExtractString; -- UNO |
SUBSTRING(s, start, length) | 从字符串 s 的 start 位置截取长度为 length 的子字符串,等同于 SUBSTR(s, start, length) | 从字符串 RUNOOB 中的第 2 个位置截取 3个 字符:SELECT SUBSTRING("RUNOOB", 2, 3) AS ExtractString; -- UNO |
SUBSTRING_INDEX(s, delimiter, number) | 返回从字符串 s 的第 number 个出现的分隔符 delimiter 之后的子串。 如果 number 是正数,返回第 number 个字符左边的字符串。 如果 number 是负数,返回第(number 的绝对值(从右边数))个字符右边的字符串。 | SELECT SUBSTRING_INDEX('a*b','*',1) -- a SELECT SUBSTRING_INDEX('a*b','*',-1) -- b SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('a*b*c*d*e','*',3),'*',-1) -- c |
TRIM(s) | 去掉字符串 s 开始和结尾处的空格 | 去掉字符串 RUNOOB 的首尾空格:SELECT TRIM(' RUNOOB ') AS TrimmedString; |
UCASE(s) | 将字符串转换为大写 | 将字符串 runoob 转换为大写:SELECT UCASE("runoob"); -- RUNOOB |
UPPER(s) | 将字符串转换为大写 | 将字符串 runoob 转换为大写:SELECT UPPER("runoob"); -- RUNOOB |
MySQL 数字函数
函数名 | 描述 | 实例 |
---|---|---|
ABS(x) | 返回 x 的绝对值 | 返回 -1 的绝对值:SELECT ABS(-1) -- 返回1 |
ACOS(x) | 求 x 的反余弦值(单位为弧度),x 为一个数值 | SELECT ACOS(0.25); |
ASIN(x) | 求反正弦值(单位为弧度),x 为一个数值 | SELECT ASIN(0.25); |
ATAN(x) | 求反正切值(单位为弧度),x 为一个数值 | SELECT ATAN(2.5); |
ATAN2(n, m) | 求反正切值(单位为弧度) | SELECT ATAN2(-0.8, 2); |
AVG(expression) | 返回一个表达式的平均值,expression 是一个字段 | 返回 Products 表中Price 字段的平均值:SELECT AVG(Price) AS AveragePrice FROM Products; |
CEIL(x) | 返回大于或等于 x 的最小整数 | SELECT CEIL(1.5) -- 返回2 |
CEILING(x) | 返回大于或等于 x 的最小整数 | SELECT CEILING(1.5); -- 返回2 |
COS(x) | 求余弦值(参数是弧度) | SELECT COS(2); |
COT(x) | 求余切值(参数是弧度) | SELECT COT(6); |
COUNT(expression) | 返回查询的记录总数,expression 参数是一个字段或者 * 号 | 返回 Products 表中 products 字段总共有多少条记录:SELECT COUNT(ProductID) AS NumberOfProducts FROM Products; |
DEGREES(x) | 将弧度转换为角度 | SELECT DEGREES(3.1415926535898) -- 180 |
n DIV m | 整除,n 为被除数,m 为除数 | 计算 10 除于 5:SELECT 10 DIV 5; -- 2 |
EXP(x) | 返回 e 的 x 次方 | 计算 e 的三次方:SELECT EXP(3) -- 20.085536923188 |
FLOOR(x) | 返回小于或等于 x 的最大整数 | 小于或等于 1.5 的整数:SELECT FLOOR(1.5) -- 返回1 |
GREATEST(expr1, expr2, expr3, …) | 返回列表中的最大值 | 返回以下数字列表中的最大值:SELECT GREATEST(3, 12, 34, 8, 25); -- 34 返回以下字符串列表中的最大值:SELECT GREATEST("Google", "Runoob", "Apple"); -- Runoob |
LEAST(expr1, expr2, expr3, …) | 返回列表中的最小值 | 返回以下数字列表中的最小值:SELECT LEAST(3, 12, 34, 8, 25); -- 3 返回以下字符串列表中的最小值:SELECT LEAST("Google", "Runoob", "Apple"); -- Apple |
LN | 返回数字的自然对数,以 e 为底。 | 返回 2 的自然对数:SELECT LN(2); -- 0.6931471805599453 |
LOG(x) 或 LOG(base, x) | 返回自然对数(以 e 为底的对数),如果带有 base 参数,则 base 为指定带底数。 | SELECT LOG(20.085536923188) -- 3 SELECT LOG(2, 4); -- 2 |
LOG10(x) | 返回以 10 为底的对数 | SELECT LOG10(100) -- 2 |
LOG2(x) | 返回以 2 为底的对数 | 返回以 2 为底 6 的对数:SELECT LOG2(6); -- 2.584962500721156 |
MAX(expression) | 返回字段 expression 中的最大值 | 返回数据表 Products 中字段 Price 的最大值:SELECT MAX(Price) AS LargestPrice FROM Products; |
MIN(expression) | 返回字段 expression 中的最小值 | 返回数据表 Products 中字段 Price 的最小值:SELECT MIN(Price) AS MinPrice FROM Products; |
MOD(x,y) | 返回 x 除以 y 以后的余数 | 5 除于 2 的余数:SELECT MOD(5,2) -- 1 |
PI() | 返回圆周率(3.141593) | SELECT PI() --3.141593 |
POW(x,y) | 返回 x 的 y 次方 | 2 的 3 次方:SELECT POW(2,3) -- 8 |
POWER(x,y) | 返回 x 的 y 次方 | 2 的 3 次方:SELECT POWER(2,3) -- 8 |
RADIANS(x) | 将角度转换为弧度 | 180 度转换为弧度:SELECT RADIANS(180) -- 3.1415926535898 |
RAND() | 返回 0 到 1 的随机数 | SELECT RAND() --0.93099315644334 |
ROUND(x [,y]) | 返回离 x 最近的整数,可选参数 y 表示要四舍五入的小数位数,如果省略,则返回整数。 | SELECT ROUND(1.23456) --1 SELECT ROUND(345.156, 2) -- 345.16 |
SIGN(x) | 返回 x 的符号,x 是负数、0、正数分别返回 -1、0 和 1 | SELECT SIGN(-10) -- (-1) |
SIN(x) | 求正弦值(参数是弧度) | SELECT SIN(RADIANS(30)) -- 0.5 |
SQRT(x) | 返回x的平方根 | 25 的平方根:SELECT SQRT(25) -- 5 |
SUM(expression) | 返回指定字段的总和 | 计算 OrderDetails 表中字段 Quantity 的总和:SELECT SUM(Quantity) AS TotalItemsOrdered FROM OrderDetails; |
TAN(x) | 求正切值(参数是弧度) | SELECT TAN(1.75); -- -5.52037992250933 |
TRUNCATE(x,y) | 返回数值 x 保留到小数点后 y 位的值(与 ROUND 最大的区别是不会进行四舍五入) | SELECT TRUNCATE(1.23456,3) -- 1.234 |
MySQL 日期函数
函数名 | 描述 | 实例 |
---|---|---|
ADDDATE(d,n) | 计算起始日期 d 加上 n 天的日期 | SELECT ADDDATE("2017-06-15", INTERVAL 10 DAY); ->2017-06-25 |
ADDTIME(t,n) | n 是一个时间表达式,时间 t 加上时间表达式 n | 加 5 秒:SELECT ADDTIME('2011-11-11 11:11:11', 5); ->2011-11-11 11:11:16 (秒) 添加 2 小时, 10 分钟, 5 秒:SELECT ADDTIME("2020-06-15 09:34:21", "2:10:5"); -> 2020-06-15 11:44:26 |
CURDATE() | 返回当前日期 | SELECT CURDATE(); -> 2018-09-19 |
CURRENT_DATE() | 返回当前日期 | SELECT CURRENT_DATE(); -> 2018-09-19 |
CURRENT_TIME | 返回当前时间 | SELECT CURRENT_TIME(); -> 19:59:02 |
CURRENT_TIMESTAMP() | 返回当前日期和时间 | SELECT CURRENT_TIMESTAMP() -> 2018-09-19 20:57:43 |
CURTIME() | 返回当前时间 | SELECT CURTIME(); -> 19:59:02 |
DATE() | 从日期或日期时间表达式中提取日期值 | SELECT DATE("2017-06-15"); -> 2017-06-15 |
DATEDIFF(d1,d2) | 计算日期 d1->d2 之间相隔的天数 | SELECT DATEDIFF('2001-01-01','2001-02-02') -> -32 |
DATE_ADD(d,INTERVAL expr type) | 计算起始日期 d 加上一个时间段后的日期,type 值可以是:MICROSECONDSECONDMINUTEHOURDAYWEEKMONTHQUARTERYEARSECOND_MICROSECONDMINUTE_MICROSECONDMINUTE_SECONDHOUR_MICROSECONDHOUR_SECONDHOUR_MINUTEDAY_MICROSECONDDAY_SECONDDAY_MINUTEDAY_HOURYEAR_MONTH | SELECT DATE_ADD("2017-06-15", INTERVAL 10 DAY); -> 2017-06-25 SELECT DATE_ADD("2017-06-15 09:34:21", INTERVAL 15 MINUTE); -> 2017-06-15 09:49:21 SELECT DATE_ADD("2017-06-15 09:34:21", INTERVAL -3 HOUR); ->2017-06-15 06:34:21 SELECT DATE_ADD("2017-06-15 09:34:21", INTERVAL -3 MONTH); ->2017-03-15 09:34:21 |
DATE_FORMAT(d,f) | 按表达式 f的要求显示日期 d | SELECT DATE_FORMAT('2011-11-11 11:11:11','%Y-%m-%d %r') -> 2011-11-11 11:11:11 AM |
DATE_SUB(date,INTERVAL expr type) | 函数从日期减去指定的时间间隔。 | Orders 表中 OrderDate 字段减去 2 天:SELECT OrderId,DATE_SUB(OrderDate,INTERVAL 2 DAY) AS OrderPayDate FROM Orders |
DAY(d) | 返回日期值 d 的日期部分 | SELECT DAY("2017-06-15"); -> 15 |
DAYNAME(d) | 返回日期 d 是星期几,如 Monday,Tuesday | SELECT DAYNAME('2011-11-11 11:11:11') ->Friday |
DAYOFMONTH(d) | 计算日期 d 是本月的第几天 | SELECT DAYOFMONTH('2011-11-11 11:11:11') ->11 |
DAYOFWEEK(d) | 日期 d 今天是星期几,1 星期日,2 星期一,以此类推 | SELECT DAYOFWEEK('2011-11-11 11:11:11') ->6 |
DAYOFYEAR(d) | 计算日期 d 是本年的第几天 | SELECT DAYOFYEAR('2011-11-11 11:11:11') ->315 |
EXTRACT(type FROM d) | 从日期 d 中获取指定的值,type 指定返回的值。 type可取值为: MICROSECONDSECONDMINUTEHOURDAYWEEKMONTHQUARTERYEARSECOND_MICROSECONDMINUTE_MICROSECONDMINUTE_SECONDHOUR_MICROSECONDHOUR_SECONDHOUR_MINUTEDAY_MICROSECONDDAY_SECONDDAY_MINUTEDAY_HOURYEAR_MONTH | SELECT EXTRACT(MINUTE FROM '2011-11-11 11:11:11') -> 11 |
FROM_DAYS(n) | 计算从 0000 年 1 月 1 日开始 n 天后的日期 | SELECT FROM_DAYS(1111) -> 0003-01-16 |
HOUR(t) | 返回 t 中的小时值 | SELECT HOUR('1:2:3') -> 1 |
LAST_DAY(d) | 返回给给定日期的那一月份的最后一天 | SELECT LAST_DAY("2017-06-20"); -> 2017-06-30 |
LOCALTIME() | 返回当前日期和时间 | SELECT LOCALTIME() -> 2018-09-19 20:57:43 |
LOCALTIMESTAMP() | 返回当前日期和时间 | SELECT LOCALTIMESTAMP() -> 2018-09-19 20:57:43 |
MAKEDATE(year, day-of-year) | 基于给定参数年份 year 和所在年中的天数序号 day-of-year 返回一个日期 | SELECT MAKEDATE(2017, 3); -> 2017-01-03 |
MAKETIME(hour, minute, second) | 组合时间,参数分别为小时、分钟、秒 | SELECT MAKETIME(11, 35, 4); -> 11:35:04 |
MICROSECOND(date) | 返回日期参数所对应的微秒数 | SELECT MICROSECOND("2017-06-20 09:34:00.000023"); -> 23 |
MINUTE(t) | 返回 t 中的分钟值 | SELECT MINUTE('1:2:3') -> 2 |
MONTHNAME(d) | 返回日期当中的月份名称,如 November | SELECT MONTHNAME('2011-11-11 11:11:11') -> November |
MONTH(d) | 返回日期d中的月份值,1 到 12 | SELECT MONTH('2011-11-11 11:11:11') ->11 |
NOW() | 返回当前日期和时间 | SELECT NOW() -> 2018-09-19 20:57:43 |
PERIOD_ADD(period, number) | 为 年-月 组合日期添加一个时段 | SELECT PERIOD_ADD(201703, 5); -> 201708 |
PERIOD_DIFF(period1, period2) | 返回两个时段之间的月份差值 | SELECT PERIOD_DIFF(201710, 201703); -> 7 |
QUARTER(d) | 返回日期d是第几季节,返回 1 到 4 | SELECT QUARTER('2011-11-11 11:11:11') -> 4 |
SECOND(t) | 返回 t 中的秒钟值 | SELECT SECOND('1:2:3') -> 3 |
SEC_TO_TIME(s) | 将以秒为单位的时间 s 转换为时分秒的格式 | SELECT SEC_TO_TIME(4320) -> 01:12:00 |
STR_TO_DATE(string, format_mask) | 将字符串转变为日期 | SELECT STR_TO_DATE("August 10 2017", "%M %d %Y"); -> 2017-08-10 |
SUBDATE(d,n) | 日期 d 减去 n 天后的日期 | SELECT SUBDATE('2011-11-11 11:11:11', 1) ->2011-11-10 11:11:11 (默认是天) |
SUBTIME(t,n) | 时间 t 减去 n 秒的时间 | SELECT SUBTIME('2011-11-11 11:11:11', 5) ->2011-11-11 11:11:06 (秒) |
SYSDATE() | 返回当前日期和时间 | SELECT SYSDATE() -> 2018-09-19 20:57:43 |
TIME(expression) | 提取传入表达式的时间部分 | SELECT TIME("19:30:10"); -> 19:30:10 |
TIME_FORMAT(t,f) | 按表达式 f 的要求显示时间 t | SELECT TIME_FORMAT('11:11:11','%r') 11:11:11 AM |
TIME_TO_SEC(t) | 将时间 t 转换为秒 | SELECT TIME_TO_SEC('1:12:00') -> 4320 |
TIMEDIFF(time1, time2) | 计算时间差值 | mysql> SELECT TIMEDIFF("13:10:11", "13:10:10"); -> 00:00:01 mysql> SELECT TIMEDIFF('2000:01:01 00:00:00', -> '2000:01:01 00:00:00.000001'); -> '-00:00:00.000001' mysql> SELECT TIMEDIFF('2008-12-31 23:59:59.000001', -> '2008-12-30 01:01:01.000002'); -> '46:58:57.999999' |
TIMESTAMP(expression, interval) | 单个参数时,函数返回日期或日期时间表达式;有2个参数时,将参数加和 | mysql> SELECT TIMESTAMP("2017-07-23", "13:10:11"); -> 2017-07-23 13:10:11 mysql> SELECT TIMESTAMP('2003-12-31'); -> '2003-12-31 00:00:00' mysql> SELECT TIMESTAMP('2003-12-31 12:00:00','12:00:00'); -> '2004-01-01 00:00:00' |
TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) | 计算时间差,返回 datetime_expr2 − datetime_expr1 的时间差 | mysql> SELECT TIMESTAMPDIFF(DAY,'2003-02-01','2003-05-01'); // 计算两个时间相隔多少天 -> 89 mysql> SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01'); // 计算两个时间相隔多少月 -> 3 mysql> SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01'); // 计算两个时间相隔多少年 -> -1 mysql> SELECT TIMESTAMPDIFF(MINUTE,'2003-02-01','2003-05-01 12:05:55'); // 计算两个时间相隔多少分钟 -> 128885 |
TO_DAYS(d) | 计算日期 d 距离 0000 年 1 月 1 日的天数 | SELECT TO_DAYS('0001-01-01 01:01:01') -> 366 |
WEEK(d) | 计算日期 d 是本年的第几个星期,范围是 0 到 53 | SELECT WEEK('2011-11-11 11:11:11') -> 45 |
WEEKDAY(d) | 日期 d 是星期几,0 表示星期一,1 表示星期二 | SELECT WEEKDAY("2017-06-15"); -> 3 |
WEEKOFYEAR(d) | 计算日期 d 是本年的第几个星期,范围是 0 到 53 | SELECT WEEKOFYEAR('2011-11-11 11:11:11') -> 45 |
YEAR(d) | 返回年份 | SELECT YEAR("2017-06-15"); -> 2017 |
YEARWEEK(date, mode) | 返回年份及第几周(0到53),mode 中 0 表示周天,1表示周一,以此类推 | SELECT YEARWEEK("2017-06-15"); -> 201724 |
MySQL 高级函数
函数名 | 描述 | 实例 |
---|---|---|
BIN(x) | 返回 x 的二进制编码,x 为十进制数 | 15 的 2 进制编码:SELECT BIN(15); -- 1111 |
BINARY(s) | 将字符串 s 转换为二进制字符串 | SELECT BINARY "RUNOOB"; -> RUNOOB |
CASE expression WHEN condition1 THEN result1 WHEN condition2 THEN result2 ... WHEN conditionN THEN resultN ELSE result END |
CASE 表示函数开始,END 表示函数结束。如果 condition1 成立,则返回 result1, 如果 condition2 成立,则返回 result2,当全部不成立则返回 result,而当有一个成立之后,后面的就不执行了。 | SELECT CASE WHEN 1 > 0 THEN '1 > 0' WHEN 2 > 0 THEN '2 > 0' ELSE '3 > 0' END ->1 > 0 |
CAST(x AS type) | 转换数据类型 | 字符串日期转换为日期:SELECT CAST("2017-08-29" AS DATE); -> 2017-08-29 |
COALESCE(expr1, expr2, …, expr_n) | 返回参数中的第一个非空表达式(从左向右) | SELECT COALESCE(NULL, NULL, NULL, 'runoob.com', NULL, 'google.com'); -> runoob.com |
CONNECTION_ID() | 返回唯一的连接 ID | SELECT CONNECTION_ID(); -> 4292835 |
CONV(x,f1,f2) | 返回 f1 进制数变成 f2 进制数 | SELECT CONV(15, 10, 2); -> 1111 |
CONVERT(s USING cs) | 函数将字符串 s 的字符集变成 cs | SELECT CHARSET('ABC') ->utf-8 SELECT CHARSET(CONVERT('ABC' USING gbk)) ->gbk |
CURRENT_USER() | 返回当前用户 | SELECT CURRENT_USER(); -> guest@% |
DATABASE() | 返回当前数据库名 | SELECT DATABASE(); -> runoob |
IF(expr,v1,v2) | 如果表达式 expr 成立,返回结果 v1;否则,返回结果 v2。 | SELECT IF(1 > 0,'正确','错误') ->正确 |
IFNULL(v1,v2) | 如果 v1 的值不为 NULL,则返回 v1,否则返回 v2。 | SELECT IFNULL(null,'Hello Word') ->Hello Word |
ISNULL(expression) | 判断表达式是否为 NULL | SELECT ISNULL(NULL); ->1 |
LAST_INSERT_ID() | 返回最近生成的 AUTO_INCREMENT 值 | SELECT LAST_INSERT_ID(); ->6 |
NULLIF(expr1, expr2) | 比较两个字符串,如果字符串 expr1 与 expr2 相等 返回 NULL,否则返回 expr1 | SELECT NULLIF(25, 25); -> |
SESSION_USER() | 返回当前用户 | SELECT SESSION_USER(); -> guest@% |
SYSTEM_USER() | 返回当前用户 | SELECT SYSTEM_USER(); -> guest@% |
USER() | 返回当前用户 | SELECT USER(); -> guest@% |
VERSION() | 返回数据库的版本号 | SELECT VERSION() -> 5.6.34 |
以下是 MySQL 8.0 版本新增的一些常用函数:
函数 | 描述 | 实例 |
---|---|---|
JSON_OBJECT() | 将键值对转换为 JSON 对象 | SELECT JSON_OBJECT('key1', 'value1', 'key2', 'value2') |
JSON_ARRAY() | 将值转换为 JSON 数组 | SELECT JSON_ARRAY(1, 2, 'three') |
JSON_EXTRACT() | 从 JSON 字符串中提取指定的值 | SELECT JSON_EXTRACT('{"name": "John", "age": 30}', '$.name') |
JSON_CONTAINS() | 检查一个 JSON 字符串是否包含指定的值 | SELECT JSON_CONTAINS('{"name": "John", "age": 30}', 'John', '$.name') |
ROW_NUMBER() | 为查询结果中的每一行分配一个唯一的数字 | SELECT ROW_NUMBER() OVER(ORDER BY id) AS row_number, name FROM users |
RANK() | 为查询结果中的每一行分配一个排名 | SELECT RANK() OVER(ORDER BY score DESC) AS rank, name, score FROM students |
运算符
本章节我们主要介绍 MySQL 的运算符及运算符的优先级。 MySQL 主要有以下几种运算符:
- 算术运算符
- 比较运算符
- 逻辑运算符
- 位运算符
算术运算符
MySQL 支持的算术运算符包括:
运算符 | 作用 |
---|---|
+ | 加法 |
- | 减法 |
* | 乘法 |
/ 或 DIV | 除法 |
% 或 MOD | 取余 |
在除法运算和模运算中,如果除数为0,将是非法除数,返回结果为NULL。
1、加
1 |
|
2、减
1 |
|
3、乘
1 |
|
4、除
1 |
|
5、商
1 |
|
6、取余
1 |
|
比较运算符
SELECT 语句中的条件语句经常要使用比较运算符。通过这些比较运算符,可以判断表中的哪些记录是符合条件的。比较结果为真,则返回 1,为假则返回 0,比较结果不确定则返回 NULL。
符号 | 描述 | 备注 |
---|---|---|
= | 等于 | |
<>, != | 不等于 | |
> | 大于 | |
< | 小于 | |
<= | 小于等于 | |
>= | 大于等于 | |
BETWEEN | 在两值之间 | >=min&&<=max |
NOT BETWEEN | 不在两值之间 | |
IN | 在集合中 | |
NOT IN | 不在集合中 | |
<=> | 严格比较两个NULL值是否相等 | 两个操作码均为NULL时,其所得值为1;而当一个操作码为NULL时,其所得值为0 |
LIKE | 模糊匹配 | |
REGEXP 或 RLIKE | 正则式匹配 | |
IS NULL | 为空 | |
IS NOT NULL | 不为空 |
1、等于
1 |
|
2、不等于
1 |
|
3、安全等于
与 = 的区别在于当两个操作码均为 NULL 时,其所得值为 1 而不为 NULL,而当一个操作码为 NULL 时,其所得值为 0而不为 NULL。
1 |
|
4、小于
1 |
|
5、小于等于
1 |
|
6、大于
1 |
|
7、大于等于
1 |
|
8、BETWEEN
1 |
|
9、IN
1 |
|
10、NOT IN
1 |
|
11、IS NULL
1 |
|
12、IS NOT NULL
1 |
|
13、LIKE
1 |
|
14、REGEXP
1 |
|
逻辑运算符
逻辑运算符用来判断表达式的真假。如果表达式是真,结果返回 1。如果表达式是假,结果返回 0。
运算符号 | 作用 |
---|---|
NOT 或 ! | 逻辑非 |
AND | 逻辑与 |
OR | 逻辑或 |
XOR | 逻辑异或 |
1、与
1 |
|
2、或
1 |
|
3、非
1 |
|
4、异或
1 |
|
位运算符
位运算符是在二进制数上进行计算的运算符。位运算会先将操作数变成二进制数,进行位运算。然后再将计算结果从二进制数变回十进制数。
运算符号 | 作用 |
---|---|
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
! | 取反 |
<< | 左移 |
>> | 右移 |
1、按位与
1 |
|
2、按位或
1 |
|
3、按位异或
1 |
|
4、按位取反
1 |
|
5、按位右移
1 |
|
6、按位左移
1 |
|
运算符优先级
最低优先级为: :=。
命令大全
基础命令
操作 | 命令 |
---|---|
连接到 MySQL 数据库 | mysql -u 用户名 -p |
查看所有数据库 | SHOW DATABASES; |
选择一个数据库 | USE 数据库名; |
查看所有表 | SHOW TABLES; |
查看表结构 | DESCRIBE 表名; 或 SHOW COLUMNS FROM 表名; |
创建一个新数据库 | CREATE DATABASE 数据库名; |
删除一个数据库 | DROP DATABASE 数据库名; |
创建一个新表 | CREATE TABLE 表名 (列名1 数据类型 [约束], 列名2 数据类型 [约束], ...); |
删除一个表 | DROP TABLE 表名; |
插入数据 | INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...); |
查询数据 | SELECT 列1, 列2, ... FROM 表名 WHERE 条件; |
更新数据 | UPDATE 表名 SET 列1 = 值1, 列2 = 值2, ... WHERE 条件; |
删除数据 | DELETE FROM 表名 WHERE 条件; |
创建用户 | CREATE USER '用户名'@'主机' IDENTIFIED BY '密码'; |
授权用户 | GRANT 权限 ON 数据库名.* TO '用户名'@'主机'; |
刷新权限 | FLUSH PRIVILEGES; |
查看当前用户 | SELECT USER(); |
退出 MySQL | EXIT; |
数据库相关命令
下面是与 MySQL 数据库操作相关的命令,包括创建、删除和修改数据库等操作:
操作 | 命令 |
---|---|
创建数据库 | CREATE DATABASE 数据库名; |
删除数据库 | DROP DATABASE 数据库名; |
修改数据库编码格式和排序规则 | ALTER DATABASE 数据库名 DEFAULT CHARACTER SET 编码格式 DEFAULT COLLATE 排序规则; |
查看所有数据库 | SHOW DATABASES; |
查看数据库详细信息 | SHOW CREATE DATABASE 数据库名; |
选择数据库 | USE 数据库名; |
查看数据库的状态信息 | SHOW STATUS; |
查看数据库的错误信息 | SHOW ERRORS; |
查看数据库的警告信息 | SHOW WARNINGS; |
查看数据库的表 | SHOW TABLES; |
查看表的结构 | DESC 表名; DESCRIBE 表名; SHOW COLUMNS FROM 表名; EXPLAIN 表名; |
创建表 | CREATE TABLE 表名 (列名1 数据类型 [约束], 列名2 数据类型 [约束], ...); |
删除表 | DROP TABLE 表名; |
修改表结构 | ALTER TABLE 表名 ADD 列名 数据类型 [约束]; ALTER TABLE 表名 DROP 列名; ALTER TABLE 表名 MODIFY 列名 数据类型 [约束]; |
查看表的创建 SQL | SHOW CREATE TABLE 表名; |
数据表相关命令
以下是与 MySQL 数据表相关的常用命令,包括创建、修改、删除表以及查看表的结构和数据等操作:
操作 | 命令 |
---|---|
创建表 | CREATE TABLE 表名 (列名1 数据类型 [约束], 列名2 数据类型 [约束], ...); |
删除表 | DROP TABLE 表名; |
修改表结构 | 添加列: ALTER TABLE 表名 ADD 列名 数据类型 [约束]; 删除列: ALTER TABLE 表名 DROP 列名; 修改列: ALTER TABLE 表名 MODIFY 列名 数据类型 [约束]; 重命名列: ALTER TABLE 表名 CHANGE 旧列名 新列名 数据类型 [约束]; |
查看表结构 | DESC 表名; DESCRIBE 表名; SHOW COLUMNS FROM 表名; EXPLAIN 表名; |
查看表的创建 SQL | SHOW CREATE TABLE 表名; |
查看表中的所有数据 | SELECT * FROM 表名; |
插入数据 | INSERT INTO 表名 (列1, 列2, ...) VALUES (值1, 值2, ...); |
更新数据 | UPDATE 表名 SET 列1 = 值1, 列2 = 值2, ... WHERE 条件; |
删除数据 | DELETE FROM 表名 WHERE 条件; |
查看表的索引 | SHOW INDEX FROM 表名; |
创建索引 | CREATE INDEX 索引名 ON 表名 (列名); |
删除索引 | DROP INDEX 索引名 ON 表名; |
查看表的约束 | SHOW CREATE TABLE 表名; (约束信息会包含在创建表的 SQL 中) |
查看表的统计信息 | SHOW TABLE STATUS LIKE '表名'; |
MySQL 事务相关命令
以下是与 MySQL 事务相关的常用命令:
操作 | 命令 |
---|---|
开始事务 | START TRANSACTION; 或 BEGIN; |
提交事务 | COMMIT; |
回滚事务 | ROLLBACK; |
查看当前事务的状态 | SHOW ENGINE INNODB STATUS; (可查看 InnoDB 存储引擎的事务状态) |
锁定表以进行事务操作 | LOCK TABLES 表名 WRITE; 或 LOCK TABLES 表名 READ; |
释放锁定的表 | UNLOCK TABLES; |
设置事务的隔离级别 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
MySQL高性能优化规范
数据库命令规范
- 所有数据库对象名称必须使用小写字母并用下划线分割
- 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来)
- 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符
- 临时库表必须以tmp_为前缀并以日期为后缀,备份表必须以bak_为前缀并以日期(时间戳)为后缀
- 所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低)
数据库基本设计规范
- 所有表必须使用Innodb存储引擎
1 |
|
- 数据库和表的字符集统一使用UTF8
1 |
|
- 所有表和字段都需要添加注释
1 |
|
- 尽量控制单表数据量的大小,建议控制在500万以内
1 |
|
- 谨慎使用Mysql分区表
1 |
|
- 尽量做到冷热数据分离,减小表的宽度
1 |
|
- 禁止在表中建立预留字段
1 |
|
- 禁止在数据库中存储图片,文件等大的二进制数据
1 |
|
-
禁止在线上做数据库压力测试
-
禁止从开发环境,测试环境直接连接生成环境数据库
数据库字段设计规范
- 优先选择符合存储需要的最小的数据类型
1 |
|
- 将字符串转换成数字类型存储,如:将IP地址转换成整形数据
mysql提供了两个方法来处理ip地址
inet_aton 把ip转为无符号整型(4-8位)
inet_ntoa 把整型的ip转为地址
插入数据前,先用inet_aton把ip地址转为整型,可以节省空间
显示数据时,使用inet_ntoa把整型的ip地址转为地址显示即可。
- 对于非负型的数据(如自增ID、整型IP)来说,要优先使用无符号整型来存储
因为:无符号相对于有符号可以多出一倍的存储空间
1 |
|
VARCHAR(N)中的N代表的是字符数,而不是字节数
使用UTF8存储255个汉字 Varchar(255)=765个字节
过大的长度会消耗更多的内存
- 避免使用TEXT、BLOB数据类型,最常见的TEXT类型可以存储64k的数据
- 建议把BLOB或是TEXT列分离到单独的扩展表中
Mysql内存临时表不支持TEXT、BLOB这样的大数据类型,如果查询中包含这样的数据,在排序等操作时,就不能使用内存临时表,必须使用磁盘临时表进行
而且对于这种数据,Mysql还是要进行二次查询,会使sql性能变得很差,但是不是说一定不能使用这样的数据类型
如果一定要使用,建议把BLOB或是TEXT列分离到单独的扩展表中,查询时一定不要使用select * 而只需要取出必要的列,不需要TEXT列的数据时不要对该列进行查询
- TEXT或BLOB类型只能使用前缀索引
因为MySQL对索引字段长度是有限制的,所以TEXT类型只能使用前缀索引,并且TEXT列上是不能有默认值的
3. 避免使用ENUM类型
修改ENUM值需要使用ALTER语句
ENUM类型的ORDER BY操作效率低,需要额外操作
禁止使用数值作为ENUM的枚举值
4. 尽可能把所有列定义为 NOT NULL
原因:索引NULL列需要额外的空间来保存,所以要占用更多的空间
进行比较和计算时要对NULL值做特别的处理
5. 使用TIMESTAMP(4个字节)或DATETIME类型(8个字节)存储时间
TIMESTAMP 存储的时间范围 1970-01-01 00:00:01 ~ 2038-01-19-03:14:07
TIMESTAMP 占用4字节和INT相同,但比INT可读性高
超出TIMESTAMP取值范围的使用DATETIME类型存储
经常会有人用字符串存储日期型的数据(不正确的做法)
1 |
|
6. 同财务相关的金额类数据必须使用decimal类型
- 非精准浮点:float,double
- 精准浮点:decimal
Decimal类型为精准浮点数,在计算时不会丢失精度
占用空间由定义的宽度决定,每4个字节可以存储9位数字,并且小数点要占用一个字节
可用于存储比bigint更大的整型数据
索引设计
常见规范
- 限制每张表上的索引数量,建议单张表索引不超过5个
1 |
|
- 禁止给表中的每一列都建立单独的索引
1 |
|
- 每个Innodb表必须有个主键
1 |
|
常见索引列建议
-
出现在SELECT、UPDATE、DELETE语句的WHERE从句中的列
-
包含在ORDER BY、GROUP BY、DISTINCT中的字段
并不要将符合1和2中的字段的列都建立一个索引, 通常将1、2中的字段建立联合索引效果更好
-
多表join的关联列
如何选择索引列的顺序
1 |
|
- 区分度最高的放在联合索引的最左侧(区分度=列中不同值的数量/列的总行数)
- 尽量把字段长度小的列放在联合索引的最左侧(因为字段长度越小,一页能存储的数据量越大,IO性能也就越好)
- 使用最频繁的列放到联合索引的左侧(这样可以比较少的建立一些索引)
避免建立冗余索引和重复索引
(增加了查询优化器生成执行计划的时间)
1 |
|
对于频繁的查询优先考虑使用覆盖索引
覆盖索引:就是包含了所有查询字段(where,select,ordery by,group by包含的字段)的索引
覆盖索引的好处:
- 避免Innodb表进行索引的二次查询
Innodb是以聚集索引的顺序来存储的,对于Innodb来说,二级索引在叶子节点中所保存的是行的主键信息,
如果是用二级索引查询数据的话,在查找到相应的键值后,还要通过主键进行二次查询才能获取我们真实所需要的数据
而在覆盖索引中,二级索引的键值中可以获取所有的数据,避免了对主键的二次查询 ,减少了IO操作,提升了查询效率
- 可以把随机IO变成顺序IO加快查询效率
由于覆盖索引是按键值的顺序存储的,对于IO密集型的范围查找来说,对比随机从磁盘读取每一行的数据IO要少的多,
因此利用覆盖索引在访问时也可以把磁盘的随机读取的IO转变成索引查找的顺序IO
索引SET规范
尽量避免使用外键约束
不建议使用外键约束(foreign key),但一定要在表与表之间的关联键上建立索引
外键可用于保证数据的参照完整性,但建议在业务端实现
外键会影响父表和子表的写操作从而降低性能
数据库SQL开发规范
- 建议使用预编译语句进行数据库操作
1 |
|
- 避免数据类型的隐式转换
1 |
|
- 充分利用表上已经存在的索引
避免使用双%号的查询条件。
如 a like ‘%123%’,(如果无前置%,只有后置%,是可以用到列上的索引的)
一个SQL只能利用到复合索引中的一列进行范围查询
1 |
|
使用left join 或 not exists 来优化not in 操作
1 |
|
-
数据库设计时,应该要对以后扩展进行考虑
-
程序连接不同的数据库使用不同的账号,进制跨库查询
1 |
|
- 禁止使用SELECT * 必须使用SELECT <字段列表> 查询
1 |
|
- 禁止使用不含字段列表的INSERT语句
1 |
|
- 避免使用子查询,可以把子查询优化为join操作
1 |
|
- 避免使用JOIN关联太多的表
1 |
|
- 减少同数据库的交互次数
1 |
|
- 对应同一列进行or判断时,使用in代替or
1 |
|
- 禁止使用order by rand() 进行随机排序
1 |
|
- WHERE从句中禁止对列进行函数转换和计算
1 |
|
- 在明显不会有重复值时使用UNION ALL 而不是UNION
1 |
|
- 拆分复杂的大SQL为多个小SQL
1 |
|
数据库操作行为规范
-
超100万行的批量写(UPDATE、DELETE、INSERT)操作,要分批多次进行操作
-
大批量操作可能会造成严重的主从延迟
主从环境中,大批量操作可能会造成严重的主从延迟,大批量的写操作一般都需要执行一定长的时间,而只有当主库上执行完成后,才会在其他从库上执行,所以会造成主库与从库长时间的延迟情况
- binlog日志为row格式时会产生大量的日志
大批量写操作会产生大量日志,特别是对于row格式二进制数据而言,由于在row格式中会记录每一行数据的修改,我们一次修改的数据越多,
产生的日志量也就会越多,日志的传输和恢复所需要的时间也就越长,这也是造成主从延迟的一个原因
- 避免产生大事务操作
大批量修改数据,一定是在一个事务中进行的,这就会造成表中大批量数据进行锁定,从而导致大量的阻塞,阻塞会对MySQL的性能产生非常大的影响
特别是长时间的阻塞会占满所有数据库的可用连接,这会使生产环境中的其他应用无法连接到数据库,因此一定要注意大批量写操作要进行分批
- 对于大表使用pt-online-schema-change修改表结构
-
避免大表修改产生的主从延迟
-
避免在对表字段进行修改时进行锁表
- 对大表数据结构的修改一定要谨慎,会造成严重的锁表操作,尤其是生产环境,是不能容忍的
pt-online-schema-change它会首先建立一个与原表结构相同的新表,并且在新表上进行表结构的修改,然后再把原表中的数据复制到新表中,并在原表中增加一些触发器
把原表中新增的数据也复制到新表中,在行所有数据复制完成之后,把新表命名成原表,并把原来的表删除掉
把原来一个DDL操作,分解成多个小的批次进行
- 禁止为程序使用的账号赋予super权限
1 |
|
- 对于程序连接数据库账号,遵循权限最小原则
1 |
|
参考资料
- https://www.runoob.com/mysql/mysql-tutorial.html
- https://javaguide.cn/database/basis.html
- https://www.cnblogs.com/huchong/p/10219318.html
文章链接:
https://www.zywvvd.com/notes/coding/dataset/mysql/mysql-tutorial/
“觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭”

微信支付

支付宝支付