写给 Poppy 的 MySQL 速查表
昨天 Poppy 问我是不是应该学一些网页开发的东西, 我的回答是这样的:
今天花了点时间汇总了一些 MySQL 简单的命令.
======== 正文分割线 ========
有哪些常见的数据库:
- Oracle
- MySQL
- SQL Server
- MongoDB
- Redis
- Hadoop
以下所有命令基于数据库 kis_blog
编写, 可以通过 Navicat 或者 DataGrip 亲自体验一下.
注:
- poppython.com 的数据库采用的是阿里云的 RDS 云数据库(MySQL);
- Navicat 和 DataGrip 是 MySQL 的 GUI 客户端;
- MySQL 搭建完毕以后可以创建多个数据库, 每个数据库可以创建多张数据表;
- 警号
#
开头的是注释; - 分号
;
结尾代表语句结束; - 本文由简入繁的顺序编写, 建议从头阅读, 不要跳过;
blogs
表结构
kis_blog
有 5 张表, 分别是:
users
: 用户表categories
: 分类表comments
: 评论表tags
: 标签表blogs
: 文章表
MySQL 的数据表类似于 Excel, 下边是表 blogs
的 Excel 描述:
上图中蓝色的文字是列, 橙色的文字是列的注释, 黑色的文字是数据, 每一行代表一条数据.
以下章节按照 crud boy
的顺序编写:
CURD 代表 CREATE(创建)、RETRIEVE(检索)、UPDATE(更新)、DELETE(删除) 几个单词的首字母
查
查询数据使用 SELECT
关键字:
# 查 blogs 的所有列
SELECT * FROM blogs;
# MySQL 的关键字不区分大小写, 下面两条语句是等价的(建议使用大写):
SELECT * FROM blogs;
select * from blogs;
# 查 blogs 的单个列
SELECT id FROM blogs;
# 查 blogs 的多个列
SELECT id, title FROM blogs;
# 去重
SELECT DISTINCT category_id FROM blogs;
排序使用 ORDER BY
关键字:
# 按照 id 排序(默认升序)
SELECT * FROM blogs ORDER BY id;
# 按照 id 升序
SELECT * FROM blogs ORDER BY id ASC;
# 按照 id 降序
SELECT * FROM blogs ORDER BY id DESC;
# 按照 id, category_id 多个列排序(默认升序)
SELECT * FROM blogs ORDER BY user_id, category_id;
# 按照 id, category_id 多个列排序(指定排序方向)
# ASC 和 DESC 只能影响到其前面的列
SELECT * FROM blogs ORDER BY user_id ASC, category_id DESC;
过滤数据使用 WHERE
关键字:
# 只看 poppy(你的 id 是 2 ) 发布的文章
SELECT * FROM blogs WHERE user_id = 2;
# 只看置顶状态的文章
# status 列存储了一个字符串有以下可选值: DRAFT(草稿)、已发布(PUBLISHED)、TOP(置顶)、HIDE(隐藏)
SELECT * FROM blogs WHERE status = 'PUBLISHED';
# 只看 id 大于 10 的文章
SELECT * FROM blogs WHERE id > 10;
# 只看 id 小于等于 2 的文章
SELECT * FROM blogs WHERE id <= 2;
# 只看 id 位于 2 和 10 之间的文章 (包括 2 也包括 10)
SELECT * FROM blogs WHERE id BETWEEN 2 AND 10;
# 只看 id 不等于 6 的文章, 以下两条语句是等价的
SELECT * FROM blogs WHERE id <> 6;
SELECT * FROM blogs WHERE id != 6;
过滤数据除了 WHERE
关键字之外, 还有 AND
、OR
、IN
、NOT
等子句可以使用:
# 查看 user_id 为 1 并且 category_id 为 2 的文章
SELECT * FROM blogs WHERE user_id = 1 AND category_id = 2;
# 查看 category_id 为 2 或者 category_id 为 3 的文章
SELECT * FROM blogs WHERE category_id = 2 OR category_id = 3;
# 猜猜这行什么意思?
SELECT * FROM blogs WHERE (category_id = 2 OR category_id = 3) AND user_id = 1;
# 查看 category_id 为 2 或者 category_id 为 3 的文章
SELECT * FROM blogs WHERE category_id IN (2, 3);
# 只看 summary 为空的文章
SELECT * FROM blogs WHERE summary IS NULL;
# 只看 summary 不为空的文章
SELECT * FROM blogs WHERE summary IS NOT NULL;
在一些后台系统中, 经常需要分页查询数据, 假如前端传递 /api/blogs?current=2&size=10
表示页码为 2, 页长为 10, 后端需要做以下处理:
# 查询第 2*10 条数据之后的 10 条数据, 也就是第 21 条到第 30 条
SELECT * FROM blogs LIMIT 2 * 10, 10;
# 查询所有数据作为 count, 后端需要返回 current, size, count 三个字段给前端
# 用于发起下一次分页查询
SELECT COUNT(id) FROM blogs;
以上查询数据的方式都是通过精确匹配, MySQL 同样支持模糊匹配.
通配查询使用 LIKE
关键字, 最常用的通配符的 %
, %
表示任意字符出现任意次数.
# 查看 title 中以 Git 开头的文章
SELECT * FROM blogs WHERE title LIKE 'Git%';
# 查看 title 中以 Git 结尾的文章
SELECT * FROM blogs WHERE title LIKE '%Git';
# 查看 title 包含 Git
SELECT * FROM blogs WHERE title LIKE '%Git%';
通过以上查询方式得到的数据就像 excel 里的行, 还可以做简单的拼接、计算:
# 给标题加上书名号
# CONCAT 函数表示将参数拼接在一起
# AS 关键字表示给拼接后的列取个新名字叫 full_title
SELECT CONCAT('《', title, '》') AS full_title FROM blogs;
# 去掉 title 的首空格
SELECT LTRIM(title) FROM blogs;
# 去掉 title 的尾空格
SELECT LTRIM(title) FROM blogs;
# 去掉 title 的首尾空格
SELECT TRIM(title) FROM blogs;
# 计算点赞率 (点赞率 = 点赞数 / 浏览数)
SELECT like_count / read_count AS like_rate FROM blogs;
MySQL 还支持以下函数:
- 文本处理类:
LEFT()
: 返回字符串左边的字符LENGTH()
: 返回字符串的长度LOWER()
: 将字符串转换为小写LTRIM()
: 去掉字符串左边的空格RIGHT()
: 返回字符串右边的字符RTRIM()
: 去掉字符串右边的空格SOUNDEX()
: 返回字符串的SOUNDEX值UPPER()
: 将字符串转换为大写
- 日期处理类:
YEAR()
: 获取年MOUNTH()
: 获取月DAY()
: 获取日NOW()
: 获取当前日期- 还有其他很多函数...
- 数值处理类:
AVT()
: 返回某列的平均值COUNT()
: 返回某列的行数MAX()
: 返回某列的最大值MIN()
: 返回某列的最小值SUM()
: 返回某列值之和ABS()
: 返回一个数的绝对值COS()
: 返回一个角度的余弦EXP()
: 返回一个数的指数值PI()
: 返回圆周率SIN()
: 返回一个角度的正弦SQRT()
: 返回一个数的平方根TAN()
: 返回一个角度的正切- 还有其他很多函数...
除了上述的各种单表查询方法外, MySQL 还支持各种姿势的联表查询 (SQL 最强大功能之一):
INNER JOIN
(内联接)OUTER JOIN
(外联接)LEFT JOIN
(左联接)LEFT OUTER JOIN
(左外联接)RIGHT JOIN
(右联接)RIGHT OUTER JOIN
(右外联接)FULL JOIN
(全连接)FULL OUTER JOIN
(全外联接)
- 交叉联接
这部分内容略多, 可以参考 Mysql表连接查询.
增
创建数据库:
# 创建数据库
# 这行语句比较复杂, 可以简单这样理解:
# 1. 如果 kis_blog 已存在的话则跳过
# 2. 如果 kis_blog 不存在则创建, 创建时:
# + 指定字符集为 utf8
# + 指定字符序为 utf8_general_ci
CREATE DATABASE IF NOT EXISTS kis_blog DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
创建数据表 blogs
:
CREATE TABLE IF NOT EXISTS `blogs`(
`id` INT UNSIGNED AUTO_INCREMENT,
`title` VARCHAR(100) NOT NULL,
`summary` VARCHAR(200),
`content ` VARCHAR(10000),
PRIMARY KEY ( `id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
创建数据表的命令比较复杂, 以上仅定义了 id、title、summary、content 四个列.
数据表的每个列都有一个类型, MySQL 提供了很多可选的选项, 在实际开发中, 程序员需要按照真实的业务情况选择合适的数据类型, 简单来说分为以下几种:
- 字符串:
CHAR
: 定长字符串VARCHAR
: 变长字符串TINYTEXT
: 短文本, 最多存储 255 个字符 (2^8-1)TEXT
: 长文本, 最多存储 65535 个字符 (2^16-1)MEDIUMTEXT
: 中等长度文本, 最多存储 16777215 个字符 (2^24-1)LONGTEXT
: 极大文本, 最多存储 4294967295 个字符 (2^32-1)- 其他二进制类型...
- 数字
TINYINT
: 小整数, 0 - 255 之间SMALLINT
: 大整数, 0 - 65535 之间MEDIUMINT
: 大整数, 0 - 16777215 之间INT
: 大整数, 0 - 4294967295 之间BIGINT
: 极大整数FLOAT
: 单精度浮点数DOUBLE
: 双精度浮点数DECIMAL
: 小数
- 日期
DATE
: 日期, 例如: 2013-07-20 (没错, 我们的纪念日)TIME
: 时间, 例如: 05:20:00DATETIME
: 混合 DATE 和 TIME, 例如: 2013-07-20 05:20:00YEAR
: 年, 例如: 2013TIMESTAMP
: 时间戳
除了数据类型外, 定义数据表还需要一些约束字段:
AUTO_INCREMENT
: 表明这个列是自增的, 常用于 id, 会从 1 开始, 每加一条数据就自动加 1 作为新增数据的id;NOT NULL
: 表明这个列是必填的, 不能为空UNIQE
: 表明这个列是唯一的PRIMARY KEY
: 表明这个列是主键, 主键很重要
关于主键:
- 主键是一条记录的唯一表示, 就像公民的身份证号码;
- 主键字段必须唯一并且非空;
- 一个表只能有一个主键;
- 主键可以包含一个字段或多个字段, 多个字段时称为 "联合主键";
关于外键:
- 外键用来表示两个表之间的关系;
- 一个表可以有多个外键;
poppython.com 的数据库里有以下场景:
有用户表 users
用来存储用户的信息, 另有文章表 blogs
, 一个用户可以有多个文章, 这种情况下, users
和 orders
是一对多的关系.
此时可以将 users.id
字段作为 blogs
表的主键, users.id
就是 users
表的外键, users
通常被称为主表, blogs
被称为子表.
创建数据使用 INSERT
关键字:
# 创建一篇示例文章
INSERT INTO blogs (
user_id,
title,
category_id,
content,
pathname,
STATUS
)
VALUES (
2,
'示例标题',
7,
'示例文章',
'test-insert',
'DRAFT'
);
改
在实际的开发过程中, 数据表设计比较复杂, 需要尽可能的满足当前甚至未来的业务, 经常需要多个程序员共同商讨.
修改数据相对来说比较简单, 修改数据表使用 ALTER
关键字, 修改数据使用 UPDATE
关键字:
# 为 blogs 添加列
ALTER TABLE blogs ADD test_column CHAR(20);
# 删除 blogs 的 test_column 列
ALTER TABLE blogs DROP COLUMN test_column;
# 将 id 为 37 的文章状态改为 "置顶"
UPDATE status = 'TOP' FROM blogs WHERE id = 37;
# 将所有文章的状态改为 "已发布"
UPDATE status = 'PUBLISHED' FROM blogs WHERE id > 0;
删
删数据也很简单, 删除数据库和数据表使用 DROP
关键字, 删除数据使用 DELETE
关键字:
# 删除数据库
DROP DATABASE db_name;
# 删除数据表
DROP TABLE table_name;
# 删除 id 为 42 的文章
DELETE FROM blogs WHERE id = 42;
其他
事务
在实际的开发中经常需要批量执行一些 SQL 语句, 并且这批 SQL 要么全部成功, 要么不执行, 这种情况下需要使用事务.
START TRANSACTION
# 批量的 SQL 语句...
COMMIT TRANSACTION
存储过程
在我的理解中, 存储过程相当于封装了 SQL 的函数.
TODO: 本王这部分的了解太浅, 暂时略过.
游标
TODO: 本王这部分的了解太浅, 暂时略过.
撤销
SQL 的 ROLLBACK 命令用来撤销 SQL 语句.
DELETE FROM table_name;
ROLLBACK;
索引
索引用来排序数据以加快搜索的速度, 索引分为:
- 普通索引
- 唯一索引
- 主键索引
# 创建普通索引
ALTER TABLE blogs ADD INDEX title;
# 创建唯一索引
ALTER TABLE blogs ADD UNIQUE pathname;
# 创建主键索引
ALTER TABLE blogs ADD PRIMARY KEY(id);
查看索引:
SHOW INDEX FROM blogs;
删除索引:
DROP INDEX title ON blogs;
ORM
从上边的原始 SQL 代码可以看到操作数据表是很复杂的, 在真实的业务中经常需要在 SQL 中需要注入变量后拼装出冗长的 SQL 语句.
ORM 解决了以上问题, ORM 是 Object Relational Mapping (对象关系映射)的简称, 可以简单理解成操作 SQL 的第三方工具包.
poppython.com 中使用了基于 Node 的 Sequelize 作为 ORM, 下面罗列了一些代码片段.
下面的代码用来创建文章, 在前端使用 POST 请求访问 /api/v1/blog
接口时, 会携带参数走到以下方法中:
async create() {
const { ctx, service } = this;
const { title, pathname, summary, tagIds, categoryId, content, status } = ctx.request.body;
const userId = ctx.helper.getLoggedIdByToken(ctx.cookies.get("tk"));
try {
const existed = await service.blog.findOne({ where: { pathname } });
if (existed) {
ctx.body = { success: false, message: ctx.__("ExistMsg", pathname) };
return;
}
const created = await service.blog.create({
title,
pathname,
summary,
userId,
categoryId,
content,
status,
});
const tags = await service.tag.findAll({ where: { id: tagIds } });
await created.setTags(tags);
ctx.body = { success: true, message: ctx.__("SuccessSmg"), data: created.id };
} catch (e) {
ctx.logger.error("Error while BlogController.create, stack: ", e);
ctx.body = { success: false, message: ctx.__("InnerErrorMsg") };
}
}
上边的代码只有常规的对象, 完全看不到原始 SQL 的影子.
MySQL 的优化
在庞大的业务数据下, MySQL 经常需要各种各样的优化方式, 比如:
- 使用缓存数据库
- 使用恰当的数据类型
- 创建高性能的索引
- 优化查询语句
- 读写分离
- 分布式数据库
- ...
- 这方面我是半桶水, 就不晃荡了...
开发一个创建文章的功能的流程
第一步: 在后端定义了一些路由地址, 比如:
// 当用于访问 /admin/write.html 时, 返回一个静态的页面
router.get("/admin/write.html", controller.view.admin.renderWrite);
// 当收到 /api/v1/blog 的POST 请求时, 执行 `controller.api.blog` 控制器的 `create` 方法
router.post("/api/v1/blog", controller.api.blog.create);
第二步: 前端创建 write.html
, 下面是伪代码:
<form id="js_writeForm" action="#">
<input type="text" name="title" placeholder="请输入标题" />
<textarea name="content" placeholder="请输入正文"></textarea>
<button type="submit">提交</button>
</form>
<script>
$(document).ready(function () {
var $writeForm = $("#js_writeForm");
// 监听表单的提交事件
$writeForm.on("submit", function (event) {
// 阻止默认的提交事件
evt.preventDefault();
// 获取表单数据
var writeFormData = $writeForm.serializeJSON();
// 发起网络请求
$.ajax({
type: "POST",
url: "/api/v1/blog",
// 在请求结束后执行一些逻辑
success: function (res) {
if (res.success) {
alert("操作成功");
} else {
alert("操作失败");
}
}
});
});
});
</script>
第三步: 后端处理前端提交的 title
, content
等数据, 将数据存入数据表, 并将存储结果返回给前端;
第四步: 前端在收到后端的返回结果后, 执行对应的消息提示;
第五步: END;
======== 本文结束 ========
2020-10-14 更新
很开心这篇文章能帮助到别人~
如果你有问题欢迎留言和我交流, 阅读原文
写给 Poppy 的 MySQL 速查表的更多相关文章
- [功能集锦] 003 - 一键生成mysql数据字典/数据库速查表
写在前面: 因为工作时候经常遇到半路接手项目的情况,由于年代久远,数据库字典这块经常缺失.故写此篇,以便复用,也希望对大家有点帮助. 随笔内容不高级,如有不妥,不吝指正. ps:有另一篇详细随笔可以参 ...
- java-Mysql-SQLServer数据类型匹配速查表
java-Mysql-SQLServer数据类型匹配速查表 Mysql ************************************ 当前列 ClassName ColumnType Di ...
- python 下的数据结构与算法---2:大O符号与常用算法和数据结构的复杂度速查表
目录: 一:大O记法 二:各函数高阶比较 三:常用算法和数据结构的复杂度速查表 四:常见的logn是怎么来的 一:大O记法 算法复杂度记法有很多种,其中最常用的就是Big O notation(大O记 ...
- Java, C#, Swift语法对比速查表
原文:Java, C#, Swift语法对比速查表 Java 8 C# 6 Swift 变量 类型 变量名; 类型 变量名; var 变量名 : 类型; 变量(类型推断) N/A var 变量名= ...
- ABP问题速查表
如果你领导要让你一夜之间掌握ABP,并且用ABP撸一个项目出来,你很可能很快速的过了一遍ABP文档就马上动手干活了.那么这篇文章就很适合你. 这篇文章列出了很多ABP新手问的问题和解答.注:有些同学问 ...
- 【转】shell速查表
shell速查表 转自:https://www.jianshu.com/p/a98a334bfb25 1. 变量 #!/bin/bash msg="hello world" ech ...
- 【转】Vim速查表-帮你提高N倍效率
Vim速查表-帮你提高N倍效率 转自:https://www.jianshu.com/p/6aa2e0e39f99 去年上半年开始全面使用linux进行开发和娱乐了,现在已经回不去windows了. ...
- GNU Emacs命令速查表
GNU Emacs命令速查表 第一章 Emacs的基本概念 表1-1:Emacs编辑器的主模式 模式 功能 基本模式(fundamental mode) 默认模式,无特殊行为 文本模式(text m ...
- bash基本命令速查表
来源:https://github.com/skywind3000/awesome-cheatsheets/blob/master/languages/bash.sh ################ ...
随机推荐
- 搜索引擎优化(SEO)解决方案
搜索引擎优化(SEO)解决方案 在此之前,希望大家能重新审视搜索引擎,通俗来讲就是我们日常所用的百度.谷歌.搜狗.雅虎等.磨刀不误砍柴工,知己知彼,百战不殆! 一.搜索引擎是什么? 搜索引擎(Se ...
- python序列(三)列表元素访问与计数
1.使用下标直接访问列表元素,如果指定下标不存在,则抛出异常. >>> alist[3] 1 >>> alist[3]=5.5 >>> alist ...
- [译] ConstraintLayout 可视化[Design]编辑器(这到底是什么)[第四部分]
原文地址:Testing Views in Isolation with Espresso 原文作者:Ataul Munim 译文出自:掘金翻译计划 译者:yazhi1992 校对者:lovexiao ...
- 查看权限详情 将部门大类单据整合,将子类单据id去重合并
/** * 查看权限详情 * @param id 部门id * @return */ @GetMapping("getListInfo") public R getDetail(S ...
- Liunx运维(八)-LIunx磁盘与文件系统管理命令
文档目录: 一.fdisk:磁盘分区工具 二.partprobe:更新内核的硬盘分区表信息 三.tune2fs:调整ext2/ext3/ext4文件系统参数 四.parted:磁盘分区工具 五.mkf ...
- [从源码学设计]蚂蚁金服SOFARegistry之服务上线
[从源码学设计]蚂蚁金服SOFARegistry之服务上线 目录 [从源码学设计]蚂蚁金服SOFARegistry之服务上线 0x00 摘要 0x01 业务领域 1.1 应用场景 1.1.1 服务发布 ...
- 基于nginx实现web服务器的双机热备
1.适用场景 对于部署重要的服务,会使用两台服务器,互相备份,共同执行同一服务.当一台服务器出现故障时,可以由另一台服务器承担服务任务,从而在不需要人工干预的情况下,自动保证系统能持续提供服务.双机热 ...
- 十八般武艺玩转GaussDB(DWS)性能调优:路径干预
摘要:路径生成是表关联方式确定的主要阶段,本文介绍了几个影响路径生成的要素:cost_param, scan方式,join方式,stream方式,并从原理上分析如何干预路径的生成. 一.cost模型选 ...
- 【SpringBoot1.x】SpringBoot1.x 入门
SpringBoot1.x 入门 文章源码 简介 传统的 JavaEE 开发,十分笨重且配置繁琐,开发效率很低,而且有很复杂的部署流程,对于第三方技术的集成也很困难. Sring 全家桶时代则解决了上 ...
- version can neither be null, empty nor blank
在用mybatis-generator逆向生成mapper和DAO的时候,出现了这个错误. mybatis-generator:generate 原因是在pom.xml中我的mysql依赖没有写版本号 ...