MySQL 基础语法
Posted Wallace JW
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL 基础语法相关的知识,希望对你有一定的参考价值。
前言
数据库管理系统(DBMS, Database Management System)主要分为关系型数据库管理系统(RDBMS)和非关系型数据库管理系统(NoSQL)两种。作为最流行的 RDBMS 之一, mysql 因为其开源、灵活高效的特性,在很多互联网公司都有着广泛的使用,并且对各种编程语言都有很好的兼容。
本文将介绍 MySQL 的基础语法,包括数据类型,数据库操作,基本 sql 语句等内容。关于 MySQL 的安装配置,可以参考教程。
文章目录
MySQL 执行过程
MySQL 是典型的 C/S 结构,架构图如下:
- 连接层: 负责建立客服端和服务端的连接
- SQL 层:负责对 SQL 进行查询和处理
- 存储引擎层:负责对数据库文件进行存储和读取
MySQL 5.5 版本后默认的存储引擎为 InnoDB,优点是支持事务,行级锁,外键约束,支持崩溃后的安全恢复。
MySQL 的执行过程为:
SQL 语句 -> 查询缓存 -> 解析器 -> 优化器 -> 执行器 -> 返回结果
MySQL Server 首先在查询缓存中检查是否有对应 sql 语句的缓存,如果有的话直接将结果返回客户端,如果没有就进入解析器,对 SQL 进行语法分析和语义分析,检查无误后,在优化器中确定 SQL 的执行路径,比如全表搜索还是索引检索等,最后在执行器中执行操作。
我们可以查看一下执行一条 sql 语句的过程中各步骤的耗时情况
SELECT @@profiling; # 查看 profiling 是否开启,若没有则需要将其开启
SET profiling = 1; # 打开 profiling 收集 MySQL 执行过程中的资源情况
SELECT * FROM user_tbl; # 执行一条 SQL 语句
SHOW profile; # 查看耗时
结果如下:
8.0 版本已经将查询缓存功能删除,原因是只要数据表发生了更新,缓存就会失效,因此查询缓存很难命中,反而增加了耗时。
SQL 类型
SQL 语句类型
介绍完 MySQL 的系统架构和执行流程,接下来开始介绍 SQL 语句,SQL 全称是 Structured Query Language 结构化查询语言,用于 RDBMS 的管理以及流处理。根据功能和操作对象来划分,SQL 通常被分为以下几类:
- DDL:Date Definition Language 数据定义语言
创建/修改/删除 数据库对象,如库、表、视图、索引等 - DML:Data Manipulation Language 数据操作语言
对数据库中的数据进行增删改查 - DCL:Data Control Language 数据控制语言
定义访问权限和安全级别 - DQL:Data Query Language 数据查询语言
专指查询语句
MySQL 数据类型
在讲解 MySQL 语法之前,我们需要先了解 MySQL 的数据类型,常用的 MySQL 数据类型有以下几大类:数值、字符串和时间。
数值类型
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT | 1 字节 | (-128,127) | (0,255) | 小整数值 |
SMALLINT | 2 字节 | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT | 3 字节 | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT或INTEGER | 4 字节 | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT | 8 字节 | (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT | 4 字节 | (-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 字节 | (-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的值 | 小数值 |
字符串类型
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255字节 | 定长字符串 |
VARCHAR | 0-65535 字节 | 变长字符串,可手动指定长度,如 VARCHAR(255) |
TINYBLOB | 0-255字节 | 不超过 255 个字符的二进制字符串 |
TINYTEXT | 0-255字节 | 短文本字符串 |
BLOB | 0-65 535字节 | 二进制形式的长文本数据 |
TEXT | 0-65 535字节 | 长文本数据 |
MEDIUMBLOB | 0-16 777 215字节 | 二进制形式的中等长度文本数据 |
MEDIUMTEXT | 0-16 777 215字节 | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295字节 | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295字节 | 极大文本数据 |
日期和时间类型
类型 | 大小 (字节) | 范围 | 格式 | 用途 |
---|---|---|---|---|
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:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
DDL
DDL 为数据定义语言,数据库对象,如库、表、视图、索引等进行增删改查操作。
Database
对数据库的常用操作为创建,选择,重命名和删除。
# 创建数据库
CREATE DATABASE database_name;
# 例子
CREATE DATABASE `wallace_local_test`;
# 选择数据库
USE database_name;
# 例子
USE `wallace_local_test`;
# 重命名数据库 (重命名之前,确保其他人没有使用该数据库,并且数据库设置为单用户模式)
ALTER DATABASE database_name MODIFY NAME = new_database_name;
# 例子
ALTER DATABASE `wallace_local_test` MODIFY NAME = `wallace_local_new`
# 删除数据库
DROP DATABASE database_name;
# 例子
DROP DATABASE `wallace_local_test`;
注意:不是引号或者双引号,是重音符号``,可用可不用
Table
日常使用的 SQL 主要就是对数据表内容的操作,
逻辑上,表由行和列组成;物理上,表具有两种数据存储单位,数据页和区。
-
数据页是最基本的数据存储单位
-
区是最基本的管理空间单位,由八个物理上连续的数据页组成,区有两种类型:
-
统一区: 由单个对象所有,区中的所有 8 页只能由所属对象使用
-
混合区: 最多可由 8 个对象共享,区中的每页可由不同的对象所有
创建和删除
# 创建表
CREATE TABLE table_name (column_name column_type); # 用逗号分隔字段
# 例子
CREATE TABLE IF NOT EXISTS `users` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NOT NULL DEFAULT ’‘ COMMENT '用户名',
`password` VARCHAR(45) NOT NULL DEFAULT ’‘ COMMENT '密码',
`status` INT NOT NULL DEFAULT 0 COMMENT '0:有效帐户 1:无效帐户',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `idx_user_01` (`name` ASC))
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8
COMMENT = '用户表';
# 删除表
DROP TABLE table_name;
# 例子
DROP TABLE `users`;
常用约束:
- AUTO_INCREMENT:自增
- NOT NULL :非空
- DEFAULT:默认值
- COMMON:字段备注
- PRIMARY KEY:主键约束,唯一 + 非空
- USING:定义索引结构,BTREE or HASH
- UNIQUE INDEX:唯一索引,在索引的基础上增加唯一性约束
- ENGINE:指定存储引擎
- DEFAULT CHARACTER SET:指定编码格式
修改表结构
修改表结构需要使用 ALTER 命令
修改表名
ALTER TABLE old_table_name RENAME TO new_table_name;
添加、修改或删除字段
# 删除字段
ALTER TABLE table_name DROP column_name;
# 添加字段 (如果要添加 NOT NULL 的字段,必选要赋默认值)
ALTER TABLE table_name ADD column_name column_type; # 默认在最后一列加
ALTER TABLE table_name ADD column_name column_type FIRST; # 在第一列加
ALTER TABLE table_name ADD column_name column_type AFTER old_column_name
# 在 old_column_name 的后面加
# 修改字段
ALTER TABLE table_name MODIFY column_name new_column_type; # 修改字段类型
ALTER TABLE table_name CHANGE old_column_name new_column_name new_column_type
# 修改字段类型和字段名,如果有不修改的内容写成和原来的一样就可以
# 修改默认值
ALTER TABLE table_name ALTER column_name SET DEFAULT default_value;
# 删除默认值
ALTER TABLE table_name ALTER column_name DROP DEFAULT;
重置自增主键 id
ALTER TABLE tablename auto_increment = new_id_value;
生成结构表格
SELECT
COLUMN_NAME 字段名,
COLUMN_TYPE 数据类型,
DATA_TYPE 字段类型,
CHARACTER_MAXIMUM_LENGTH 长度,
IS_NULLABLE 是否允许空值,
COLUMN_DEFAULT 默认值,
COLUMN_COMMENT 备注
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE
table_schema ='database_name'
AND TABLE_NAME = 'table_name';
基本 DML 语句
插入数据
INSERT INTO table_name ( field1, field2,...fieldN )
VALUES
( value1, value2,...valueN );
注意:
- 自增字段不需要赋值
- 指定了默认值的字段,如果没有被赋值,自动赋默认值
- NOT NULL 且没有默认值的字段,如果没有赋值,会报错
- 如果字段类型与赋值类型不一致,会报错
查询数据
整体结构
MySQL 查询语句的关键词顺序有严格的规定,顺序不对就会报错,关键词顺序为:
SELECT...DISTINCT...FROM...JOIN...WHERE...GROUP BY...HAVING...ORDER BY...LIMIT...OFFSET
MySQL 的查询语句基本语法如下, SELECT 关键字后为输出的字段,用逗号分隔,FROM 指定数据表,其他关键字的含义后面会分别介绍
SELECT column_name, column_name..... # 顺序 5
FROM table1 JOIN table2 ON table1.id = table2.id # 顺序 1
WHERE conditions # 顺序 2
GROUP BY table1.id # 顺序 3
HAVING num > 2 # 顺序 4
ORDER BY field1 [ASC [DESC]] # 顺序 6
[LIMIT N][ OFFSET M] # 顺序 7
代码中的注释为 SELECT 语句各个部分的执行顺序,在数据库底层实现中,每一个步骤都会生成一个虚拟表,来作为下一个步骤的输入,直至产生最终的结果。
提高 SELECT 效率的简单技巧
- 如果事先确定只有一条结果,可以加上 limit 1,这样查出一条数据就会返回,可以避免全局扫描
- 在实际开发中,应该坚决避免
SELECT *
,因为SELECT *
会返回所有数据,其中有很多是我们并不需要的,这样会增大数据表查询的网络传输量,而且会导致全表扫描而不是索引扫描,严重影响查询效率。
在实际开发中,我们不应该依赖数据表设计时的默认值,否则有可能出现数据表设计时的默认值跟代码业务逻辑中的默认值不一致的情况,因此通常会在 select 手动指定字段为空时的默认值,如:
SELECT IFNULL(user_name, "") AS user_name FROM user_tbl;
DISTINCT
如果需要读取不重复的数据可以在 SELECT 语句中使用 DISTINCT 关键字来过滤重复数据。
SELECT DISTINCT last_name, first_name FROM person_tbl;
要注意的是, DISTINCT
是对所有需要查询列名的组合去重,因此必须放在所有列名的最前面,放在其他位置会报错。
WHERE
[WHERE condition1 [AND [OR][NOT]] condition2.....]
可以用于 select, update 和 delete 语句,操作符包括 =
, <>/!=
, >
, <
, <=
, >=
, BETWEEN. .. AND ...
, IS NULL
,当 AND
和 OR
同时存在的时候,AND
的优先级大于 OR
如果字段有多个满足条件的取值,用 IN 来包含,如:
WHERE id IN (1,2,3,4,5)
可以使用 like 子句和通配符进行模糊匹配,_
表示单个字符的模糊匹配,%
表示 n 个字符的模糊匹配,如:
WHERE name LIKE '%Jia%'
但是需要注意,即使 name 字段已经建立索引,使用 %
作为开头来进行模糊搜索,也会导致不走索引进行全表扫描,效率很低,不推荐使用(但是 %
作为结尾的时候会走索引)。
常用的通配符有:
- %:表示任意 0 个或多个字符。可匹配任意类型和长度的字符,有些情况下若是中文,使用两个百分号(%%)表示。
- _:表示任意单个字符。匹配单个任意字符,它常用来限制表达式的字符长度语句。
ORDER BY
可以使用 MySQL 的 ORDER BY 子句来设定你想按哪个字段哪种方式来进行排序,再返回搜索结果。
SELECT field1, field2,...fieldN FROM table_name1, table_name2...ORDER BY field1 [ASC [DESC]], [field2...] [ASC [DESC]]
如果要对多个字段排序,用逗号分隔,按顺序先对第一个字段排序,第一个字段相同时再按第二个字段排序,以此类推。
ASC 升序,DESC 降序,默认为 ASC。
LIMIT & OFFSET
LIMIT 表示需要查询的行数,OFFSET 表示偏移量,OFFSET n 表示结果忽略前 n 条,例如 OFFSET 2, 则从结果中的第 3 条开始输出。
LIMIT M, OFFSET N
等价于 LIMIT N, M
UNION
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。
SELECT expression1, expression2, ... expression_n
FROM tables
WHERE conditions
UNION [ALL | DISTINCT]
SELECT expression1, expression2, ... expression_n
FROM tables
WHERE conditions;
- DISTINCT: 可选,删除结果集中重复的数据。默认情况下 UNION 操作符已经删除了重复数据,所以 DISTINCT 修饰符对结果没啥影响。
- ALL: 可选,返回所有结果集,包含重复数据。
注意,union 的字段必须相同,否则会报错
GROUP BY
GROUP BY 语句根据一个或多个列对结果集进行分组,在分组的列上我们可以使用 COUNT, SUM, AVG 等函数。
SELECT column_name, function(column_name)
FROM table_name
WHERE Clause
GROUP BY column_name;
如下表:
GROUP BY 通常跟聚集函数一起使用,比如 COUNT(), MAX(), MIN(), SUM(), AVG()
,如下面的例子,按名字进行分组,并统计每个名字有多少条记录。
SELECT name, COUNT(*) FROM employee_tbl GROUP BY name;
结果为:
如果要对分组内容进行筛选,不是用 WHERE 语句,而是用 HAVING 语句,如下:
SELECT name, COUNT(*) FROM employee_tbl GROUP BY name HAVING COUNT(*) = 2;
Group by 之后也还可以使用 WITH ROLLUP
可以实现在分组统计数据基础上再进行相同的统计。
可以使用 coalesce 来设置一个可以取代 NULL 的名称,如果不使用这个语句,rollup 那一行显示为 NLL。
select coalesce(a,b,c);
参数说明:如果 a != null, 则选择 a,如果 a = null, 则选择b;如果 b = null,则选择 c;如果 a b c 都为null ,则返回为null(没意义)。
例如,在分组求和的基础上对所得结果在进行一次求和,如果名字为空我们使用“总数”代替:
SELECT coalesce(name, '总数'), SUM(singin) AS singin_count
FROM employee_tbl
GROUP BY name WITH ROLLUP;
结果为:
修改数据
UPDATE table_name
SET field1=new-value1,
field2=new-value2
WHERE Clause
可以使用 replace 替换某个字段里的所有字符,如将 password 里的所有 W 改为 J:
UPDATE users
SET PASSWORD = REPLACE(PASSWORD, 'W', 'J')
WHERE NAME = 'Wallace';
UPDATE 语句也可以使用 CASE...WHEN...THEN
来实现类似编程语言中的 switch case
操作,
UPDATE user_tbl SET user_name = CASE id
WHEN 1 THEN 'a'
WHEN 2 THEN 'b'
WHEN 3 THEN 'c'
END
等价于
UPDATE user_tbl SET user_name = 'a' where id = 1
UPDATE user_tbl SET user_name = 'b' where id = 2
UPDATE user_tbl SET user_name = 'c' where id = 3
删除语句
DELETE FROM table_name WHERE Clause
警告:如果没有指定 WHERE 子句,MySQL 表中的所有记录将被删除。
Join
实际应用中,经常需要从多个数据表中读取数据,可以在 SELECT, UPDATE 和 DELETE 语句中使用 Mysql 的 JOIN 来联合多表查询。
JOIN 按照功能大致分为如下三类:
- INNER JOIN(内连接,或等值连接):也可以直接用 join,获取两个表中字段匹配关系的记录。
- LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录。
- RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。
如下两张表:
INNER JOIN
INNER JOIN 获取两个表中字段匹配关系的记录,可以理解为取交集。
SELECT a.id, a.author, b.count
FROM table2 a INNER JOIN table1 b ON a.author = b.author;
# 等价于:
SELECT a.id, a.author, b.count
FROM table2 a, table1 b
WHERE a.author = b.author;
结果为:
LEFT JOIN
MySQL LEFT JOIN 会读取左边数据表的全部数据,即便右边表无对应数据
SELECT a.id, a.author, b.count
FROM table2 a LEFT JOIN table1 b ON a.author = b.author;
结果为:
RIGHT JOIN
MySQL RIGHT JOIN 会读取右边数据表的全部数据,即便左边边表无对应数据。
SELECT a.id, a.author, b.count
FROM table2 a RIGHT JOIN table1 b ON a.author = b.author;
结果为:
子查询
子查询表示将一次 SELECT 语句的执行结果嵌入到另一个 SELECT 语句中,从而实现非常灵活的查询。
比如想查询 user_tbl 中的某个用户名在 booking_tbl 中购买的商品,除了将两张表通过 user_id 连接后再查询之外,也可以使用如下子查询实现。
SELECT product_id
From booking_tbl
WHERE user_id = (
SELECT id
FROM user_tbl
WHERE user_name = 'wallace'
);
非关联子查询
在上述例子中,外层查询和子查询之间相互独立,两次查询没有任何直接的关联关系,这种子查询叫非关联子查询
,执行时,先执行子查询,再将结果集传给外层查询,子查询只执行一次。
关联子查询
如果外层查询和子查询之间有关联关系,比如子查询中存在 user_tbl.id = booking_tbl.user_id
,那这种查询叫关联子查询,执行时,外层查询得到每一条数据之后都会将该条数据传入子查询中去执行一次子查询来验证是否匹配,因此效率很低,使用的时候一定要慎重。
以上是关于MySQL 基础语法的主要内容,如果未能解决你的问题,请参考以下文章