MySQL 基础 — 从建库到多表查询的第一次数据库旅程¶
这一章讲什么: 前面七章都在学「怎么算」,从这一章开始学「怎么存」。 你会从零建一个数据库、建表、选数据类型、插数据,然后学会查、改、删、排序、分组、多表联查—— 一趟完整的旅程,终点是「两张表靠一列共同的 ISBN 缝在一起」。 原书用一张存文学经典的
classics表走完全程,我们也照它的教法接住。 不需要任何数据库经验,每个术语第一次出现都当场解释。
1. 顶层全景:四个词,三种门¶
先把数据库的全部概念压缩到一张图:
数据库 publications(一个项目的数据的总容器)
└── 表 classics(一种实物的格子)
├── 行 = 一条记录(一本具体的经典)
│ 列:author | title | type | year | isbn
└── 每格 = 一个字段的具体值('Mark Twain')
图说:库套表,表装行,行分格列。Excel 文件的「工作簿/工作表/行/列」是同构的比喻。
数据库(database)的定义原书写得很干:「结构化的记录集合,组织方式让它能被快速检索」1。
里面的 SQL 三个字母是 Structured Query Language(结构化查询语言)——
一门「松散基于英语」的语言,SELECT title FROM publications WHERE author = 'Charles Dickens'
基本就是英语句子,而且同门语法也用在 Oracle、SQL Server 等其他数据库上2。
和 MySQL 说话有三扇门:命令行(本章主角)、图形工具(如 MySQL Workbench、 phpMyAdmin,以及 VS Code/PhpStorm 的插件)、编程语言(第 10 章的 PHP)3。 学命令行不是因为它是最好的门,而是因为它不遮羞——每一条命令、每一个错误都摊在面前, 图形界面把什么藏了起来,你得先在命令行里见过。
2. 走进命令行¶
2.1 登录¶
AMPPS 装好 MySQL 之后,初始用户是 root、密码是 mysql(教学默认值,别带进生产)。
macOS 上的登录命令是 /Applications/ampps/mysql/bin/mysql -u root -pmysql——
-u 后接用户名,-p 后紧跟密码(中间无空格)4。
进来的第一件事,发一条验收命令:
能看到系统自带的几行数据库名单(如 information_schema、mysql),说明整条链路通了。
如果连不上报 Can't connect to local MySQL server through socket,
九成是 MySQL 服务没启动——回 AMPPS 控制面板点 Start5。
三条登录的额外经验,原书散在各平台说明里,收拢如下:
- 远程服务器经 SSH 登录后,用管理员给你的用户名密码连; 有的主机商要求你的库名带唯一前缀(防止用户之间撞名)6。
- 密码可以贴在
-p后面省得交互输入,但这是坏习惯:同机其他人可能看到你的命令行历史, 密码就这么泄了7。 - 一旦进来,Windows/macOS/Linux 就没区别了——命令和报错全平台一致8。
2.2 分号与六个提示符¶
MySQL 命令行第一个要习惯的规矩:每条命令以分号结尾;漏了,MySQL 不换行执行,
而是换个提示符等你续完9。这是故意的——SQL 命令往往很长,分号让你能跨多行输入,
回车只是换行不是提交。常见的「卡住」几乎都是漏分号:补一个 ; 再回车就好10。
六个提示符,等于六种「MySQL 正在等你什么」的状态11:
| 提示符 | 意思 |
|---|---|
mysql> |
就绪,等你下一条命令 |
-> |
在等一条多行命令的下一行 |
'> |
单引号字符串没关 |
"> |
双引号字符串没关 |
`> |
反引号(标识符引用)没关 |
/*> |
注释没关 |
看到带引号的提示符,先想想是不是哪个字符串没闭合——这是排错的第一线索。
输入到一半想整段作废?敲 \c 回车,MySQL 丢弃已输入的内容、给一个新提示符。
注意:如果还开着引号/注释,先把它关上再 \c,否则 \c 会被当成字符串内容12。
3. 建库、建用户、授权¶
3.1 两个大小写规矩¶
SQL 的关键字不区分大小写:CREATE、create、CrEaTe 一样;
习惯上写大写是为了在满眼小写的命令里一眼看到骨架13。
表名分平台:Linux/macOS 敏感、Windows 不敏感——一律小写表名,和上一章「文件名一律小写」
是同一条移植性纪律14。
3.2 建库¶
CREATE DATABASE 建容器,返回的 Query OK, 1 row affected 是成功信号;
USE 切换进这个库,返回 Database changed——之后的命令都默认作用于当前库15。
3.3 用户与授权:最小权限原则¶
为什么不直接让 PHP 脚本用 root?原书一句话点破: 你不会想把 root 权限授给 PHP 脚本——一旦网站被黑,那就是数据库的全部权限拱手让人16。 所以标准动作是两步:
CREATE USER 'jim'@'localhost' IDENTIFIED BY 'password';
GRANT ALL ON publications.* TO 'jim'@'localhost';
第一句造用户:'用户名'@'主机名' 是账号的完整形态(同名的用户从不同主机登录可以是不同账号),
IDENTIFIED BY 设密码。第二句授权:publications.* 表示「publications 库的全部对象」——
GRANT 的目标可以细到 库.表,也可以宽到 *.*(所有库所有表)17。
两条附带的安全提醒:你只能授出自己已经有的权限;建新用户不指定密码 = 无密码账号,极其危险18。
这套「按需授权」的思路叫最小权限原则——之后的章节里,每个连接数据库的脚本都该有自己的专用账号。
4. 建表:classics 表的诞生(主线例子开始)¶
旅程的主角上场——一张存文学经典的表:
CREATE TABLE classics (
author VARCHAR(128),
title VARCHAR(128),
type VARCHAR(16),
year CHAR(4)) ENGINE InnoDB;
逐件拆:① CREATE TABLE 表名 起头;② 括号里是列清单,每列「列名 + 数据类型」;
③ 末尾的 ENGINE InnoDB 指定存储引擎(MySQL 内部处理数据的引擎有多种,
InnoDB 从 5.6 起是默认,支持事务和 FULLTEXT,写上只为显式)19。
成功返回 Query OK, 0 rows affected——0 行是因为建的是结构不是数据20。
验收工具 DESCRIBE:DESCRIBE classics; 把表的结构列成六列——Field(列名)、
Type(类型)、Null(允许空吗)、Key(索引)、Default(默认值)、Extra(附加规则)。
原书称它是「invaluable debugging aid」:表建得对不对、列名类型记不清,都靠它21。
走完这步,我们的主线例子有了空地;下面给它选格子的大小(数据类型),再往里搬数据。
5. 数据类型:每个格子该多大¶
数据类型 = 每列能装什么、装多少。选型的总原则原书给了两次:选「够用」里最小的—— 省磁盘、访问快;过大的类型是纯浪费,过小的类型装不下或截断22。
5.1 字符串家族¶
| 类型 | 存储 | 特点 |
|---|---|---|
CHAR(n) |
定长 n 字节 | 不满 n 用空格补齐;CHAR(5) 存 "Hello" 用 5 字节 |
VARCHAR(n) |
变长,最多 n | 按实际长度存;"Hello" 在 VARCHAR(7) 里用 5 字节 + 少量管理开销 |
TEXT 系(TINYTEXT→LONGTEXT) |
变长大文本 | 不能有默认值;索引只索引前 n 个字符 |
BINARY/VARBINARY/BLOB 系 |
二进制字节 | 无字符集概念,适合图片等 |
CHAR 与 VARCHAR 的选择判据:长度都差不多 → CHAR(省管理开销); 长度参差 → VARCHAR(省空间)23。超长的处理:塞得比声明长,MySQL 直接截断到上限—— 原书提醒你知道这个行为24。TEXT 与 VARCHAR 的边界:要全文搜 → VARCHAR; 只搜前若干字符 → TEXT 也行25。
5.2 数值家族与「带符号」¶
| 类型 | 字节 | 有符号范围 | 无符号范围 |
|---|---|---|---|
| TINYINT | 1 | -128 ~ 127 | 0 ~ 255 |
| SMALLINT | 2 | -32768 ~ 32767 | 0 ~ 65535 |
| MEDIUMINT | 3 | 约 ±8.4 百万 | 0 ~ 约 1677 万 |
| INT | 4 | 约 ±21.5 亿 | 0 ~ 约 42.9 亿 |
| BIGINT | 8 | 约 ±9.2 × 10¹⁸ | 0 ~ 约 1.8 × 10¹⁹ |
| FLOAT / DOUBLE | 4 / 8 | 浮点(只能有符号) | —— |
「有符号 / 无符号」原书的比喻最好:同样的位数,有符号像把数轴左移一半——
负数占一半,正数占一半;无符号从 0 起全给正数。计数器、年份这类永不为负的,
加 UNSIGNED 白赚一倍上限:INT UNSIGNED26。
两个易混点,原书专门纠正:
INT(4)的 4 不是存储字节数,是显示宽度;它只在与ZEROFILL联用时才可见—— 不足 4 位的前补零(0071)。存储范围照旧由 INT 本身决定27。- 没有
INT(n)限定存储大小这回事——字节数永远是表左列那些固定值。
5.3 日期时间家族¶
DATETIME、DATE、TIMESTAMP、TIME、YEAR。DATETIME 与 TIMESTAMP 显示格式一样,
区别在范围和自动性:TIMESTAMP 范围窄(1970–2037)但能「你不填,它自动填当前时间」,
还能设成每次改行自动更新;DATETIME 装得下几乎任何日期但没有这个自动功能28。
5.4 AUTO_INCREMENT:给每行发一个唯一的号¶
怎么保证每一行都独一无二?作者可能重复、年份可能重复——靠数据本身保证唯一既容易错,
在多个脚本同时插行时又根本做不到。通解:加一列专职发号,
AUTO_INCREMENT 属性让它自动等于「上一行的值 + 1」,第一行从 1 开始,往后递增29:
一次见四个新词:ALTER TABLE(改已有表,和 CREATE 类似但作用于现存结构)、
NOT NULL(此列不许空——NULL 意味着「无值」,发号列里绝不允许)、
AUTO_INCREMENT(自动发号)、KEY(把它设成索引,因为你会常按它查行)30。
当然也能在建表时一步到位(例 8-6);练完用 ALTER TABLE classics DROP id; 删掉31。
ALTER 一族的其他动作,顺手收齐:
| 动作 | 命令 |
|---|---|
| 改表名 | ALTER TABLE classics RENAME pre1900; |
| 改列类型 | ALTER TABLE classics MODIFY year SMALLINT;(数据能转则自动转) |
| 加列 | ALTER TABLE classics ADD pages SMALLINT UNSIGNED; |
| 改列名 | ALTER TABLE classics CHANGE type category VARCHAR(16);(必须连类型重写) |
| 删列 | ALTER TABLE classics DROP pages; |
| 删表 | DROP TABLE disposable; |
DROP 不可逆——Warning 原书给得毫不含糊:手滑能删掉整张表甚至整个库32。
5.5 搬数据:INSERT¶
INSERT INTO classics(author, title, type, year)
VALUES('Mark Twain','The Adventures of Tom Sawyer','Fiction','1876');
结构两截:INSERT INTO 表名(列清单) 指定往哪几列塞,VALUES(值清单) 给出值——
两边个数必须相等、顺序必须对应:顺序一错,数据就进了错的列(「更安全」的写法第 9 章讲)33。
连插五行后,SELECT * FROM classics; 第一次展示全表——注意此时行的顺序没有保证,
排序要轮到 ORDER BY 登场34。多行也能一条 INSERT:VALUES (...), (...), (...) 逗号连排,
是原书顺手教的快捷写法35。
6. 索引:给表配目录¶
6.1 为什么需要¶
表小到几百行,直接全表扫没问题;再大下去,每次查询都翻遍所有行—— 原书的比方:像查资料要翻遍图书馆的每一本书。索引就是图书馆的卡片目录: 费一点内存和磁盘,换检索时的闪电速度36。
6.2 普通索引与前缀索引¶
ALTER TABLE classics ADD INDEX(author(20));
ALTER TABLE classics ADD INDEX(title(20));
ALTER TABLE classics ADD INDEX(category(4));
ALTER TABLE classics ADD INDEX(year);
括号里的 20 是前缀长度:索引只存每行前 20 个字符——
存 "The Adventures of Tom Sawyer" 只记 "The Adventures of To"。
为什么截短?索引越小,占空间越少、查得越快;代价是前 20 字符相同的两个条目,
MySQL 得回表里确认到底哪行匹配,浪费一点时间。
原书选 20 的依据:这两个列大多在前 20 字符内就能区分37。
DESCRIBE 验收时,被索引列的 Key 栏出现 MUL——表示「可重复值」,正是作者、书名该有的样子38。
等价写法:CREATE INDEX author ON classics (author(20));——和 ALTER 版等价,
只是它不能建主键39。索引在建表时一起规划更好:往大表补索引很耗时;
海量数据先入库、后建 FULLTEXT,避免建数据的过程中反复更新索引40。
6.3 PRIMARY KEY:整行的身份证¶
普通索引只管「快查」;主键(primary key)管「唯一」:它的每一行值都不许重复、不许为 NULL。 classics 表的最佳主键候选是 ISBN——国际公认、每书唯一。但有个坑:
原因:表已有五行数据,新列默认是 NULL,五行的 NULL 撞了「必须唯一」的规矩。 正解三步走:先无索引地加列 → 用 UPDATE 填上每行的 ISBN → 再补 PRIMARY KEY41:
ALTER TABLE classics ADD isbn CHAR(13);
UPDATE classics SET isbn='9781598184891' WHERE year='1876';
/* …其余四行同理… */
ALTER TABLE classics ADD PRIMARY KEY(isbn);
(UPDATE 和 WHERE 马上细讲;这里借年份先定位各行,因为现数据里年份恰好唯一。) 原书点出这个练习暗含的道理:用唯一键查行,比用作者名之类可重复的列更可预测—— Mark Twain 以后可能再加书,ISBN 永远只指一本42。
6.4 FULLTEXT:全文搜索引擎¶
FULLTEXT 索引把列里每个词都收进一张特殊索引,于是可以像用搜索引擎那样自然语言搜索。 三条须知:① 只能建在 CHAR/VARCHAR/TEXT 上;② 5.6 起 InnoDB 才支持(此前是 MyISAM 的专利); ③ 有个 stopword(停用词)清单——the、as、is、of 这类高频而无检索价值的词被直接忽略, 清单有 500 多个词,省空间也提速43。
加在 author、title 两列上——原书畅想:要是把全书正文也入库, 配上 FULLTEXT 就成了一台文学搜索引擎44。
7. 查询:SELECT 全家¶
7.1 骨架与两个计数器¶
something 可以是 *(所有列)、列名清单、COUNT(*)(行数)。
SELECT COUNT(*) FROM classics; 返回 5——五行数据,和原书插的一致45。
(Linux 下 pager less; 能让输出分页、nopager; 取消,大表浏览小技巧46。)
7.2 DISTINCT:去重¶
SELECT author FROM classics; 在 Dickens 有两本书时会打出他两次;
SELECT DISTINCT author FROM classics; 相同的只留一次——
DISTINCT 就是查询结果的去重开关47。
7.3 DELETE 与 WHERE:先瞄准,再开火¶
DELETE 永远该带 WHERE——不带的话是删全表。原书把 WHERE 称为「the heart and soul of SQL」: 它用布尔条件圈定哪些行中招,条件写错,删的就是错的行(或不匹配删了个寂寞)48。 WHERE 的弹药:
- 精确匹配:
WHERE author="Mark Twain"、WHERE isbn="9781598184891"。 两条查询现在结果相同,但 Mark Twain 的书会增多、ISBN 永远唯一——用唯一键定位,结果可预测49。 - LIKE 模式匹配:
%是通配符,放前面表示「前面任意」,放后面表示「后面任意」, 前后都放表示「中间夹这个」;它也能匹配空串50: WHERE author LIKE "Charles%"→ Charles Darwin 和 Charles Dickens 都中;WHERE title LIKE "%Species"→ 只有 The Origin of Species;WHERE title LIKE "%and%"→ Pride and Prejudice 和 Romeo and Juliet。- 逻辑组合:AND、OR、NOT(LIKE 也有反义 NOT LIKE)任意混排:
author LIKE "Charles%" AND author LIKE "%Darwin"(全名的 Charles Robert Darwin 也能中)、author LIKE "%Mark Twain%" OR author LIKE "%Samuel Langhorne Clemens%"(笔名或真名)51。
7.4 LIMIT:截断与翻页¶
LIMIT 3 取前三行;LIMIT 1,2 跳过 1 行取 2 行;LIMIT 3,1 跳过 3 行取 1 行。
口诀:第一个参数是「跳过几行」,第二个是「取几行」——Warning 原书特意加了框:
偏移从 0 开始数、行数从 1 开始数,LIMIT 1,3 是「跳过第 1 行、取 3 行」,
即第 2、3、4 行52。LIMIT 就是网页分页(第 10 页、每页 20 条)背后的机制。
7.5 MATCH...AGAINST:对 FULLTEXT 提问¶
自然语言模式:给几个词,任一位置的任意次序都算中;
大小写不敏感;stopword 直接跳过——查 'and' 在 MyISAM 下恒为空集,
在 InnoDB 下却可以查到(引擎的停用词表不同)53。
布尔模式(加 IN BOOLEAN MODE)是搜索引擎的进阶语法54:
| 写法 | 意思 |
|---|---|
+charles -species |
必须含 charles,且不得含 species |
"origin of" |
精确短语(引号内 stopword 也生效) |
例:AGAINST('+charles -species' IN BOOLEAN MODE) 只回 Dickens 的
The Old Curiosity Shop——Darwin 那行被 -species 一票否决55。
7.6 UPDATE、ORDER BY、GROUP BY¶
UPDATE 改值,语法骨架和 SELECT 同源:UPDATE classics SET author='Mark Twain (Samuel Langhorne Clemens)' WHERE author='Mark Twain';——
SET 列出新值,WHERE 圈定哪些行;第二条命令把三行的 Fiction 改成 Classic Fiction,
一行还是三百行被波及,全看 WHERE 的圈56。
ORDER BY 排序:默认升序;DESC 降序,且只作用于它前面的那一列——
ORDER BY category,year DESC 是「类别升序、同类别内年份降序」57。
GROUP BY 分组统计:SELECT category,COUNT(author) FROM classics GROUP BY category;
按类别分组、数每组的行数,输出三类各几本的汇总表58。
和 DISTINCT 的区别(章末问答题的标准答案):DISTINCT 只是去重显示;
GROUP BY 先分组、还能对每组跑 COUNT/SUM 等聚合——GROUP BY 是带着计算器去重的。
8. 连接表:两张表缝成一张视图¶
8.1 靠共同列缝合¶
再建一张 customers 表,三列客户和他们买的书(存的也是 ISBN)。
它和 classics 的缝合点是 isbn 列——同名列、同含义:一个 ISBN 永远指同一本书59。
于是:
结果:每个客户名旁边列出他买的那本书的作者和标题—— 「谁买了什么」这个分散在两表中的问题,一条查询缝合回答60。 原书预告:连接是个大题目,这里飞快掠过;第 9 章的规范化(normalization)才是系统解法61。
8.2 三种等价写法与 AS¶
同一件事,三种写法,结果一模一样62:
-- ① 逗号 + WHERE 连接条件(上面那个)
-- ② NATURAL JOIN:自动找同名列缝合
SELECT name,author,title FROM customers NATURAL JOIN classics;
-- ③ JOIN...ON:显式声明缝合列
SELECT name,author,title FROM customers
JOIN classics ON customers.isbn=classics.isbn;
AS 起别名,省打字也护眼睛:customers AS cust, classics AS class WHERE cust.isbn=class.isbn——
表名缩短,列前缀跟着短。AS 也能给列起别名:SELECT name AS customer FROM customers ORDER BY customer;
(输出表头变成 customer,排序按这个新名字走)63。
9. 收尾三件套:MySQL 函数、phpMyAdmin、本章旅程总结¶
MySQL 内置函数存在的理由,原书一句话:它们在数据所在的地方干活。 换成 PHP 做同样的事,你得先把原始数据拽出数据库、加工、再查一遍; 内置函数省掉往返,复杂查询更简单更快(字符串、日期函数各有一箩筐,细节查文档)64。
phpMyAdmin 是浏览器里的 MySQL 图形管家:AMPPS 装好就能用,
开 http://localhost/phpmyadmin,默认登录 root/mysql。建库、建表、建索引全能点出来。
原书的态度值得原样接住:命令必须先学会(图形界面背后就是这些命令),
但学会之后,图形工具确实更快更简单65。
旅程到此的全貌:从空库出发,会了建库建表、类型与 ALTER、五种索引、 SELECT 全家、两表三式连接。下一章(第 9 章)把「怎么设计才高效」补上; 第 10 章让 PHP 进场——这些命令将从「人手敲」变成「程序发」。
10. 作者的判断与证据¶
| 书中的说法 | 成色 |
|---|---|
| 别给 PHP 脚本 root 权限 | 安全基线,机制解释(被黑即全权限丢失)一句到位,是本章最该带走的一条16 |
| 索引「费一点空间换闪电速度」 | 机制性陈述,图书馆卡片目录的比喻贴切;「几百行以下不用索引」是经验值,非实测36 |
| FULLTEXT 停用词表「500 多个词」 | 具体数字,出自 MySQL 文档口径;不同引擎(InnoDB/MyISAM)的词表不同,书中以对照方式呈现43 |
| 用唯一键查询「更可预测」 | 设计经验,ISBN vs 作者名的对比论证干净,是主键价值的最佳教学瞬间49 |
| 「LIMIT 的偏移从 0 起」 | 语言事实,原书专门 Warning 框提醒——常见错,值得框52 |
| 图形工具「先学命令再用」 | 教学主张,不是技术结论;但理由(知道工具背后是什么)对初学者成立65 |
11. 边界与局限¶
- 事务、外键、视图一概没出现:InnoDB 选了,但它的看家本领(事务)要到第 9 章才露面; 外键约束(数据库层面保证引用完整性)全书基本缺席——多表连接靠「约定」而非「约束」维持。
- 连接只讲内连接:LEFT JOIN、RIGHT JOIN 这些「保留左/右表全部行」的变体没有讲, 连接大家族只开了 NATURAL/ON 两扇窗;查询里有匹配不上行的客户时会静默消失, 这个行为差异要补 LEFT JOIN 才能解决。
- 规范化只是预告:「库该怎么设计」这个大问题,本章用 Note 框指给第 9 章, 于是本章的多表例子(customers 存 isbn)其实是反规范化的——明白这一点,第 9 章会更有收获。
- 数据类型的选择停留在「够用就好」:字符集(utf8mb4)、排序规则(collation) 对中文网站是生死攸关的两项,本章未提;原书只在 CHAR 一节捎带了一句「可以为列指定字符集」23。
- SQL 注入的预防缺席:本章所有命令都是人手敲的;一旦第 10 章把这些命令拼成 PHP 字符串, 注入风险就来了——原书把防线(预处理语句)放到了第 10 章,顺序合理,但读者要带着「命令拼串很危险」 的警觉走过去。
- AMPPS 默认口令 root/mysql:教程的方便之门,生产环境的灾难之门; 书中未强调「部署第一件事改口令」,属于教材常见的默认配置盲区。
12. 章末自测:原书的问答题怎么答¶
| 原书的问题 | 我们的回答 |
|---|---|
| 分号的作用? | 命令结束符;漏了 MySQL 换提示符等你续完,也借此支持多行命令9 |
| 看有哪些库/表? | SHOW databases; / SHOW tables;3 |
| 建 newuser@localhost、密码 newpass、全权访问 newdatabase? | CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'newpass'; + GRANT ALL ON newdatabase.* TO 'newuser'@'localhost';17 |
| 看表结构? | DESCRIBE 表名;(六列:Field/Type/Null/Key/Default/Extra)21 |
| 索引的目的? | 用少量空间换检索速度,免全表逐行扫描36 |
| FULLTEXT 的好处? | 整列文本的自然语言搜索,像搜索引擎43 |
| 什么是 stopword? | 太常见而无检索价值、被 FULLTEXT 忽略的词(如 the、of),500+ 个43 |
| DISTINCT 与 GROUP BY 的区别? | 前者只去重显示;后者分组并允许聚合(COUNT 等)58 |
| 查 author 含 Langhorne 的行? | SELECT * FROM classics WHERE author LIKE '%Langhorne%';50 |
| 两表能连接的前提? | 有一列同义(如两表都存 isbn 且 ISBN 恒指同一本书)59 |
13. 可带走的¶
- 四个词:库装表、表装行、行分列为字段;SQL 是「松散基于英语」的命令语言1。
- 命令行三规矩:分号结尾、小写表名、密码别贴
-p后面9。 CREATE DATABASE建、USE进;CREATE USER+GRANT按最小权限授权17。CREATE TABLE列名配类型;DESCRIBE验收;ALTER TABLE改名/改类型/加列/删列;DROP 不可逆21。- 类型选型:够用里最小;永不为负加 UNSIGNED;
INT(4)是显示宽度不是字节数26。 - AUTO_INCREMENT 专职发号;NOT NULL 守门;主键 = 唯一 + 不空,最佳人选是 ISBN 这类天然唯一键29。
- 索引 = 目录:普通索引可重复(MUL)、前缀截短换速度;FULLTEXT 收词入索引,stopword 被忽略36。
- SELECT 骨架 + WHERE(=、LIKE 的 %、AND/OR/NOT)+ LIMIT(跳几,取几)+ DISTINCT + ORDER BY(单列升降序)+ GROUP BY(分组聚合)。
- MATCH...AGAINST 用自然语言问 FULLTEXT;布尔模式
+必须 -排除 "精确短语"54。 - DELETE/UPDATE 永远带 WHERE——WHERE 是 SQL 的心脏48。
- 两表靠同名列连接:逗号+WHERE、NATURAL JOIN、JOIN...ON 三式等价;AS 起别名60。
- 命令学透之后,phpMyAdmin 之类的图形工具是加速器,不是替代品65。
14. 原文地图¶
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| MySQL 的分量与数据库定义 | Chapter 8. Introduction to MySQL | text/11-ch08-chapter-8-introduction-to-mysql.txt:7(搜「10 million」)· :20(搜「structured collection」) |
| SQL 与示例查询 | 同上 | text/11-ch08-chapter-8-introduction-to-mysql.txt:24(搜「loosely based on English」)· :29(搜「SELECT title FROM publications」) |
| 三种访问方式 | 同上 | text/11-ch08-chapter-8-introduction-to-mysql.txt:126(搜「three main ways」)· :135(搜「Workbench」) |
| 登录与验收 | Starting the Command-Line Interface | text/12-fm-starting-the-command-line-interface.txt:86(搜「initial AMPPS MySQL user」)· :98(搜「SHOW databases」)· :107(搜「Can't connect」) |
| 分号与六个提示符 | Using the Command-Line Interface | text/13-fm-using-the-command-line-interface.txt:14(搜「semicolon is used by MySQL」)· :27(搜「six different prompts」)· :91(搜「meaningless gibberish」) |
| 大小写规矩与建库 | MySQL Commands | text/14-fm-mysql-commands.txt:133(搜「case-insensitive」)· :139(搜「Table names are case-sensitive」)· :156(搜「CREATE DATABASE」) |
| 用户与授权 | 同上 | text/14-fm-mysql-commands.txt:176(搜「grant your PHP scripts」)· :225(搜「CREATE USER 'jim'」)· :272(搜「no password」) |
| 建表与 ENGINE | 同上 | text/14-fm-mysql-commands.txt:302(搜「CREATE TABLE classics」)· :314(搜「default storage engine」)· :351(搜「DESCRIBE classics」)· :385(搜「invaluable debugging aid」) |
| 字符串与 TEXT/BLOB 类型 | Data Types | text/15-fm-data-types.txt:17(搜「truncated to the maximum length」)· :121(搜「TEXT fields」)· :133(搜「first n characters」)· :193(搜「Binary Large Object」) |
| 数值类型与 UNSIGNED/ZEROFILL | 同上 | text/15-fm-data-types.txt:242(搜「smallest data type」)· :246(搜「signed number」)· :351(搜「display width」)· :356(搜「ZEROFILL」) |
| 日期时间与 TIMESTAMP | 同上 | text/15-fm-data-types.txt:384(搜「DATETIME」)· :411(搜「very narrow range」)· :415(搜「automatically inserted」) |
| AUTO_INCREMENT 与 ALTER 一族 | 同上 | text/15-fm-data-types.txt:426(搜「error-prone」)· :444(搜「AUTO_INCREMENT」)· :493(搜「CREATE TABLE classics」)· :519(搜「DROP id」)· :693(搜「irreversible」) |
| INSERT 与顺序不定 | 同上 | text/15-fm-data-types.txt:540(搜「INSERT INTO classics」)· :564(搜「order is unspecified」) |
| 索引的理由与前缀 | Creating an Index | text/16-fm-creating-an-index.txt:14(搜「Adding indexes」)· :27(搜「first 20 characters」)· :41(搜「going to the table」)· :49(搜「key MUL」) |
| CREATE INDEX/建表时建索引/先装数据后建索引 | 同上 | text/16-fm-creating-an-index.txt:76(搜「CREATE INDEX author」)· :87(搜「time-consuming」)· :239(搜「much faster to load」) |
| 主键与回填 ISBN | 同上 | text/16-fm-creating-an-index.txt:133(搜「ADD isbn」)· :135(搜「Duplicate entry」)· :144(搜「Populating the isbn」) |
| FULLTEXT 与 stopwords | 同上 | text/16-fm-creating-an-index.txt:202(搜「every word」)· :209(搜「stopwords」)· :221(搜「only with」)· :256(搜「ADD FULLTEXT」) |
| SELECT/COUNT/DISTINCT/DELETE | Querying a MySQL Database | text/17-fm-querying-a-mysql-database.txt:35(搜「SELECT something」)· :66(搜「result returned is 5」)· :87(搜「weed out」)· :145(搜「DELETE FROM」)· :153(搜「heart and soul」) |
| WHERE、LIKE、LIMIT | 同上 | text/17-fm-querying-a-mysql-database.txt:174(搜「Mark Twain」)· :183(搜「pattern matching」)· :199(搜「empty string」)· :231(搜「LIMIT 3」)· :240(搜「offsets start at 0」) |
| MATCH...AGAINST 与布尔模式 | 同上 | text/17-fm-querying-a-mysql-database.txt:264(搜「empty set」)· :275(搜「AGAINST('and')」)· :301(搜「must be present」)· :317(搜「BOOLEAN MODE」) |
| UPDATE/ORDER BY/GROUP BY | 同上 | text/17-fm-querying-a-mysql-database.txt:361(搜「UPDATE classics SET」)· :375(搜「affected three rows」)· :400(搜「ORDER BY author」)· :424(搜「single column」)· :444(搜「GROUP BY category」) |
| 多行 INSERT 与连接三式 | Joining Tables | text/18-fm-joining-tables.txt:48(搜「shortcut for inserting」)· :70(搜「FROM customers,classics」)· :98(搜「automatically joins」)· :118(搜「JOIN classics ON」)· :133(搜「AS cust」) |
| 逻辑运算符与收尾 | Using Logical Operators | text/19-fm-using-logical-operators.txt:16(搜「AND author」)· :37(搜「right there in the database」)· :52(搜「quicker and simpler」)· :61(搜「phpmyadmin」) |
-
出处:「Chapter 8. Introduction to MySQL」第 20 段(
text/11-ch08-chapter-8-introduction-to-mysql.txt:20,搜「structured collection」)。 ↩↩ -
出处:「Chapter 8. Introduction to MySQL」第 24 段(
text/11-ch08-chapter-8-introduction-to-mysql.txt:24,搜「loosely based on English」)。「This language is loosely based on English and also used in other databases such as Oracle and Microsoft SQL Server」。 ↩ -
出处:「Chapter 8. Introduction to MySQL」第 126 段(
text/11-ch08-chapter-8-introduction-to-mysql.txt:126,搜「three main ways」)。命令行、phpMyAdmin、编程语言三扇门;SHOW 命令清单见「MySQL Commands」第 90 段(text/14-fm-mysql-commands.txt:90,搜「SHOW」)。 ↩↩ -
出处:「Starting the Command-Line Interface」第 86 段(
text/12-fm-starting-the-command-line-interface.txt:86,搜「initial AMPPS MySQL user」)与第 91 段(:91,搜「mysql -u root -pmysql」)。 ↩ -
出处:「Starting the Command-Line Interface」第 107 段(
text/12-fm-starting-the-command-line-interface.txt:107,搜「Can't connect」)与第 98 段(:98,搜「SHOW databases」)。 ↩ -
出处:「Starting the Command-Line Interface」第 176 段(
text/12-fm-starting-the-command-line-interface.txt:176,搜「preface all database names」)。 ↩ -
出处:「MySQL Commands」第 265 段(
text/14-fm-mysql-commands.txt:265,搜「poor practice」)。「this is considered poor practice because... they may be able to look at the command you entered」。 ↩ -
出处:「Using the Command-Line Interface」第 5 段(
text/13-fm-using-the-command-line-interface.txt:5,搜「identical」)。「all the commands used (and errors you may receive) are identical」。 ↩ -
出处:「Using the Command-Line Interface」第 14 段(
text/13-fm-using-the-command-line-interface.txt:14,搜「semicolon is used by MySQL」)。「The semicolon is used by MySQL to separate or end commands」;漏分号的表现见第 21 段。 ↩↩↩ -
出处:「Using the Command-Line Interface」第 21 段(
text/13-fm-using-the-command-line-interface.txt:21,搜「forgot the final semicolon」)。 ↩ -
出处:「Using the Command-Line Interface」第 27 段(
text/13-fm-using-the-command-line-interface.txt:27,搜「six different prompts」)。Table 8-2 列出全部六个。 ↩ -
出处:「Using the Command-Line Interface」第 81 段(
text/13-fm-using-the-command-line-interface.txt:81,搜「don't wish to execute」)与第 95 段(:95,搜「close it first」)。 ↩ -
出处:「MySQL Commands」第 133 段(
text/14-fm-mysql-commands.txt:133,搜「case-insensitive」)。「SQL commands and keywords are case-insensitive」。 ↩ -
出处:「MySQL Commands」第 139 段(
text/14-fm-mysql-commands.txt:139,搜「Table names are case-sensitive」)。「For the sake of portability, you should always choose a case and stick to it. The recommended style is to use lowercase」。 ↩ -
出处:「MySQL Commands」第 156 段(
text/14-fm-mysql-commands.txt:156,搜「CREATE DATABASE」)与第 163 段(:165,搜「Database changed」)。 ↩ -
出处:「MySQL Commands」第 176 段(
text/14-fm-mysql-commands.txt:176,搜「grant your PHP scripts」)。「you probably won't want to grant your PHP scripts root access to MySQL—it could cause a real headache should you get hacked」。 ↩↩ -
出处:「MySQL Commands」第 185 段(
text/14-fm-mysql-commands.txt:185,搜「CREATE USER 'username'」)与第 193 段(:193,搜「Table 8-4」)。*.*/database.*/database.object三档见 GRANT 参数表。 ↩↩↩ -
出处:「MySQL Commands」第 272 段(
text/14-fm-mysql-commands.txt:272,搜「no password」)。「if you create a new user but do not specify an IDENTIFIED BY clause, the user will have no password, a situation that is very insecure」。 ↩ -
出处:「MySQL Commands」第 306 段(
text/14-fm-mysql-commands.txt:306,搜「ENGINE InnoDB」)与第 314 段(:314,搜「default storage engine」)。「From version 5.6 onward InnoDB is the default storage engine... we use it here because it supports FULLTEXT searches」。 ↩ -
出处:「MySQL Commands」第 342 段(
text/14-fm-mysql-commands.txt:342,搜「Query OK, 0 rows affected」)。 ↩ -
出处:「MySQL Commands」第 385 段(
text/14-fm-mysql-commands.txt:385,搜「invaluable debugging aid」)。「The DESCRIBE command is an invaluable debugging aid when you need to ensure that you have correctly created a MySQL table」;六列含义在同段展开。 ↩↩↩ -
出处:「Data Types」第 242 段(
text/15-fm-data-types.txt:242,搜「smallest data type」)。「you are well advised to choose the smallest data type that will adequately handle the largest value you expect」;字符串版同义句在第 182 段。 ↩ -
出处:「Data Types」第 1–32 段(
text/15-fm-data-types.txt:5,搜「VARCHAR stands for」)。CHAR 补齐与 VARCHAR 变长的对比;字符集一句见第 13 段(「You can assign the character set to a character or text column」);截断行为见第 17 段。 ↩↩ -
出处:「Data Types」第 17 段(
text/15-fm-data-types.txt:17,搜「truncated to the maximum length」)。「if you ever attempt to assign a string value longer than the length allowed, it will be truncated」。 ↩ -
出处:「Data Types」第 140 段(
text/15-fm-data-types.txt:140,搜「better and faster」)。「VARCHAR is the better and faster data type to use if you need to search the entire contents of a field」。 ↩ -
出处:「Data Types」第 246 段(
text/15-fm-data-types.txt:246,搜「signed number」)。「picture a signed number as being shifted halfway to the left」;范围表见 Table 8-10(第 251 段起)。 ↩↩ -
出处:「Data Types」第 351 段(
text/15-fm-data-types.txt:351,搜「display width」)。「It may seem counterintuitive, but what the number actually represents is the display width」;ZEROFILL 行为在同段。 ↩ -
出处:「Data Types」第 411 段(
text/15-fm-data-types.txt:411,搜「very narrow range」)与第 415 段(:415,搜「automatically inserted」)。「If you don't specify the value when adding a row, the current time is automatically inserted」。 ↩ -
出处:「Data Types」第 426 段(
text/15-fm-data-types.txt:426,搜「error-prone」)。「This approach is error-prone and works only in certain circumstances... It is also difficult to guarantee unique rows when multiple scripts can insert rows into the same table in parallel」;通解(extra column)在第 430 段。 ↩↩ -
出处:「Data Types」第 444 段(
text/15-fm-data-types.txt:444,搜「AUTO_INCREMENT」)。四部件逐一解释见第 448–473 段;「The first starting at 1 and the others counting upward」在第 479 段。 ↩ -
出处:「Data Types」第 493 段(
text/15-fm-data-types.txt:493,搜「CREATE TABLE classics」)与第 519 段(:519,搜「DROP id」)。 ↩ -
出处:「Data Types」第 693 段(
text/15-fm-data-types.txt:693,搜「irreversible」)。「Remember that DROP is irreversible」。 ↩ -
出处:「Data Types」第 575 段(
text/15-fm-data-types.txt:575,搜「INSERT INTO classics」)与第 583 段(:583,搜「one-to-one correspondence」)。「If you accidentally listed the columns in a different order from the data, the data would go into the wrong columns」;更安全的写法预告在同段。 ↩ -
出处:「Data Types」第 558 段(
text/15-fm-data-types.txt:558,搜「SELECT * FROM classics」)与第 564 段(:564,搜「order is unspecified」)。 ↩ -
出处:「Joining Tables」第 48 段(
text/18-fm-joining-tables.txt:48,搜「shortcut for inserting multiple rows」)。单行多值 INSERT 的写法。 ↩ -
出处:「Data Types」第 741 段(
text/15-fm-data-types.txt:741,搜「every new row added」)与第 745 段(:745,搜「card index」)。「at the expense of a slight overhead in memory and disk space, you can create a 'card index' for a table」。 ↩↩↩↩ -
出处:「Creating an Index」第 27 段(
text/16-fm-creating-an-index.txt:27,搜「first 20 characters」)与第 41 段(:41,搜「going to the table」)。「If MySQL finds two indexes with the same contents, it will have to waste time going to the table itself」;20 的选法在同段。 ↩ -
出处:「Creating an Index」第 49 段(
text/16-fm-creating-an-index.txt:49,搜「key MUL」)。「This key means that multiple occurrences of a value may occur within that column」。 ↩ -
出处:「Creating an Index」第 65 段(
text/16-fm-creating-an-index.txt:65,搜「CREATE INDEX」)。「They are equivalent, except that CREATE INDEX cannot be used for creating a PRIMARY KEY」。 ↩ -
出处:「Creating an Index」第 87 段(
text/16-fm-creating-an-index.txt:87,搜「time-consuming」)与第 239 段(:239,搜「much faster to load」)。 ↩ -
出处:「Creating an Index」第 133 段(
text/16-fm-creating-an-index.txt:133,搜「ADD isbn」)与第 135 段(:135,搜「Duplicate entry」)。「If there were no data already in the table, this command would work just fine」;三步走见第 139–156 段。 ↩ -
出处:「Querying a MySQL Database」第 179 段(
text/17-fm-querying-a-mysql-database.txt:179,搜「more predictable」)。「searches using a unique key are more predictable」。 ↩ -
出处:「Creating an Index」第 202 段(
text/16-fm-creating-an-index.txt:202,搜「every word」)与第 209 段(:209,搜「stopwords」)。「a built-in list of more than 500 words」;CHAR/VARCHAR/TEXT 限制见第 227 段。 ↩↩↩↩ -
出处:「Creating an Index」第 256 段(
text/16-fm-creating-an-index.txt:256,搜「ADD FULLTEXT」)与第 260 段(:260,搜「entire text」)。 ↩ -
出处:「Querying a MySQL Database」第 66 段(
text/17-fm-querying-a-mysql-database.txt:66,搜「result returned is 5」)。「As you'd expect, the result returned is 5, as there are five publications in the table」。 ↩ -
出处:「Querying a MySQL Database」第 19 段(
text/17-fm-querying-a-mysql-database.txt:19,搜「pager less」)。 ↩ -
出处:「Querying a MySQL Database」第 87 段(
text/17-fm-querying-a-mysql-database.txt:87,搜「weed out multiple entries」)。 ↩ -
出处:「Querying a MySQL Database」第 153 段(
text/17-fm-querying-a-mysql-database.txt:153,搜「heart and soul」)。「So now we'll spend some time on that clause, which is the heart and soul of SQL」。 ↩↩ -
出处:「Querying a MySQL Database」第 179 段(
text/17-fm-querying-a-mysql-database.txt:179,搜「more predictable」)。 ↩↩ -
出处:「Querying a MySQL Database」第 183 段(
text/17-fm-querying-a-mysql-database.txt:183,搜「pattern matching」)与第 199 段(:199,搜「empty string」)。「The % will also match if there is nothing in the position it occupies」。 ↩↩ -
出处:「Using Logical Operators」第 16–24 段(
text/19-fm-using-logical-operators.txt:16,搜「AND author」)。三个查询的解释在第 24 段:「starts with Charles and ends with Darwin」。 ↩ -
出处:「Querying a MySQL Database」第 240 段(
text/17-fm-querying-a-mysql-database.txt:240,搜「offsets start at 0」)。「So, LIMIT 1,3 means return three rows starting from the second row」。 ↩↩ -
出处:「Querying a MySQL Database」第 260 段(
text/17-fm-querying-a-mysql-database.txt:260,搜「natural-language searches」)与第 264 段(:264,搜「empty set」)。「because and is a stopword in that engine, MySQL will ignore it and the query will always produce an empty set」。 ↩ -
出处:「Querying a MySQL Database」第 293 段(
text/17-fm-querying-a-mysql-database.txt:293,搜「Boolean mode」)与第 301 段(:301,搜「must be present」)。+「This word must be present」、-「its presence disqualifies the row」。 ↩↩ -
出处:「Querying a MySQL Database」第 331 段(
text/17-fm-querying-a-mysql-database.txt:331,搜「Old Curiosity Shop」)。布尔查询结果的解释;短语查询中 of 被引号激活见第 338 段。 ↩ -
出处:「Querying a MySQL Database」第 361 段(
text/17-fm-querying-a-mysql-database.txt:361,搜「UPDATE classics SET」)与第 375 段(:375,搜「affected three rows」)。 ↩ -
出处:「Querying a MySQL Database」第 400 段(
text/17-fm-querying-a-mysql-database.txt:400,搜「ORDER BY author」)与第 424 段(:424,搜「single column」)。「The DESC keyword applies only to the preceding column」。 ↩ -
出处:「Querying a MySQL Database」第 439 段(
text/17-fm-querying-a-mysql-database.txt:439,搜「how many publications of each category」)。GROUP BY 例与输出表。 ↩↩ -
出处:「Joining Tables」第 60 段(
text/18-fm-joining-tables.txt:60,搜「same meaning in both tables」)。「Because it has the same meaning in both tables (an ISBN refers to a book, and always the same book), we can use this column to tie the two tables together」。 ↩↩ -
出处:「Joining Tables」第 70 段(
text/18-fm-joining-tables.txt:70,搜「FROM customers,classics」)与第 89 段(:89,搜「neatly linked」)。三行联查输出见第 83–87 段。 ↩↩ -
出处:「Joining Tables」第 12 段(
text/18-fm-joining-tables.txt:12,搜「normalization」)。「In Chapter 9, you'll also learn more about database design, which includes a process called database normalization」。 ↩ -
出处:「Joining Tables」第 98 段(
text/18-fm-joining-tables.txt:98,搜「automatically joins columns」)、第 112 段(:112,搜「identical to those of Example 8-29」)、第 127 段(:127,搜「aliases」)。三种写法的等价性原书逐条声明。 ↩ -
出处:「Joining Tables」第 133 段(
text/18-fm-joining-tables.txt:133,搜「AS cust」)与第 154 段(:154,搜「AS customer」)。 ↩ -
出处:「Using Logical Operators」第 37 段(
text/19-fm-using-logical-operators.txt:37,搜「right there in the database」)。「If you were to use PHP, you would first have to extract raw data from MySQL, manipulate it, and then perform the database query you wanted」。 ↩ -
出处:「Using Logical Operators」第 52 段(
text/19-fm-using-logical-operators.txt:52,搜「quicker and simpler」)。「once you understand them, it can be much quicker and simpler to use a program such as phpMyAdmin」;「to use MySQL you have to learn these main commands」在同段。 ↩↩↩