🐬 第3章 使用MySQL
📄 一句话概括

每次开工的前三十秒都是同一套动作: 连上去、选库、看表。 Demo 在样例库上把这三步走了一遍——库里有六张表, 行数分别是 6/13/5/5/11/4;看表结构拿到五个字段的类型和约束。 顺带撞出一个真差异:SQLite 的 TEXT 主键允许 NULL,MySQL 的主键一律非空。

📝 本章和前面几章的关系

前两章是背景,这一章开始动手。 教材 3.1~3.3 三节加起来只有四页,但它给的三个命令(连接、USE、 SHOW)是后面 27 章每次都要用的。 这一章还顺手把全书的舞台搭好——vendors、products、customers、orders、orderitems、 productnotes 六张表,后面每条 SQL 都在这上面转。

一、连接:一行命令,四个参数

教材给的连接命令是:mysql -h 主机名 -u 用户名 -p。 四个参数记住就行: -h(host)主机、-u(user)用户、-p(password)密码、还有可选的 -P(大写,端口)。 -p 后面不跟密码,回车后它会单独问你要——这是故意的:密码写在命令行里会留在 shell 历史记录中, 别人翻一下就有了。 连不上时按三站排查,顺序别乱:先 ping 主机(网络通不通),再试 3306 端口(服务在不在听), 最后看账号密码(权限对不对)。谁先失败,问题就在哪一站。 退出用 exit 或 quit,后面要加分号也行。 命令行里还有一个 \q,效果一样——这是 mysql 客户端自己的命令,不是 SQL。 这里有个容易搞混的点:SQL 语句要分号结尾,而客户端命令(exit、quit、\s、\u)不需要。 分号是给 SQL 的,不是给客户端的。

二、选择数据库:库是表的上一级

连上去之后还没有选中任何库。 这时候敲 SELECT 会报 No database selected——这个报错新手一天能撞三次。 选库用 USE 库名;。选了之后,你写的表名都默认在这个库里找。 想换就再 USE 一次,没有「退出当前库」这种命令,直接换就行。 层级关系是三层:服务器 → 数据库 → 表 → 行。 一台服务器上可以有几十个库,一个库里有几十张表。 权限也是按层给的:可以只让你看某一个库(第 28 章)。 SQLite 没有这个层级:一个文件就是一个库,打开文件就等于选中了它。 所以本课的 Demo 里你找不到 USE,只有 connect。 这不是 SQLite 偷懒,是它的设计前提就是「单文件、单用户」。

三、了解数据库和表:三条命令摸清地形

到了一个新库,先摸地形。 MySQL 里三条命令:SHOW DATABASES;(有哪些库)、SHOW TABLES;(这个库有哪些表)、 DESCRIBE 表名;(这张表什么结构)。 DESCRIBE 的输出有五列:Field(字段名)、Type(类型)、Null(能不能空)、 Key(是不是主键/索引)、Default(默认值)、Extra(自增之类的附加信息)。 这五列就是一张表的身份证。 DESCRIBE 可以简写成 DESC,也可以写成 SHOW COLUMNS FROM 表名;,三个写法等价。 另外 SHOW CREATE TABLE 表名; 会把建表语句原样打出来—— 这个更有用,因为它连字符集、引擎、索引一起给你。 SQLite 里这三件事要绕一下:SHOW TABLES 换成查系统表 sqlite_master, DESCRIBE 换成 PRAGMA table_info(表名)。信息一样,问法不同。 摸地形这件事值得养成习惯。 拿到一个陌生库,先看有哪些表、每张表几个字段、 哪几个是主键——这三眼下去,数据模型就八九不离十了。

四、动手 Demo:连上样例库,摸一遍地形

样例库就是教材附录 B 的六张表,表结构和字段名照抄,数据按同样的量级自造。 Demo 做四件事:列出所有表、看清 products 的结构、数出每张表的行数、试一次完全限定的表名。 行数那一段是全课的坐标——后面讲一条 SQL 有没有筛对,靠的就是这些数。

import sqlite3

con = sqlite3.connect(":memory:")

# 库里有哪些表(MySQL 里是 SHOW TABLES;)
rows = con.execute("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
print([r[0] for r in rows])

# 这张表长什么样(MySQL 里是 DESCRIBE 表名;)
for r in con.execute("PRAGMA table_info(products)"):
    print(r)

实跑输出:

--------------------------------------------------------------------
第三课:连上去,看看库里有什么
--------------------------------------------------------------------

  连库之后第一件事:这个库里有哪些表
  SQL> SELECT name, type FROM sqlite_master WHERE type = 'table' ORDER BY name
  name             type
  -----------------------
  customers        table
  orderitems       table
  orders           table
  productnotes     table
  products         table
  vendors          table
  (6 行)
  MySQL 里这一句是 **SHOW TABLES;**,SQLite 没有这个命令,
  改查系统表 sqlite_master——**同样的信息,两种问法。**

  第二件事:这张表长什么样(字段、类型、能不能空、是不是主键)
  字段名        类型          能否为空    默认值      主键
  ------------------------------------------------------------
  prod_id       TEXT          是          无          是
  vend_id       INTEGER       否          无
  prod_name     TEXT          否          无
  prod_price    REAL          否          无
  prod_desc     TEXT          是          无
  MySQL 里这一句是 **DESCRIBE products;** 或 **SHOW COLUMNS FROM products;**。
  注意 prod_id 那一格:「能否为空」写的是「是」。
  **这是 SQLite 的历史包袱——它的主键允许 NULL(只拦重复值,不拦空)。**
  MySQL 的主键一律「非空且唯一」,所以这一格在 MySQL 里会是「否」。

  第三件事:每张表有几行
  表                  行数
  ------------------------------
  vendors             6
  products            13
  customers           5
  orders              5
  orderitems          11
  productnotes        4
  **这六张表就是全书的舞台**:供货商、产品、顾客、订单、订单明细、产品备注。
  后面 27 章的每一条 SQL,都是在这六张表上转。

  换个说法看同一份数据:完全限定的表名
  SQL> SELECT products.prod_name FROM products LIMIT 3
  prod_name
  -------------
  .5 ton anvil
  1 ton anvil
  2 ton anvil
  (3 行)
  **表名.字段名** 的写法,在只查一张表时是多余的;
  但一牵扯到多张表(第 15 章联结),它就是必需品——不然两个表都有 prod_name 时,
  数据库不知道你说的是谁的。

第一张表是「这个库里有什么」。 六张表一次列清:供货商、产品、顾客、订单、订单明细、产品备注。 MySQL 里这一句是 SHOW TABLES,SQLite 查 sqlite_master——同一个问题,两种问法。 第二张表是「这张表长什么样」。 五个字段:prod_id 文本主键、vend_id 整数、prod_name 文本、 prod_price 实数、prod_desc 文本。 prod_desc 那两格都写着「是」——它既允许空、也不是主键,所以插数据时可以不给它值。 prod_id 那一格值得停一下:「能否为空」写的是「是」。 这是 SQLite 的历史包袱—— 它的主键只拦重复值、不拦空值。 MySQL 的主键一律「非空且唯一」,这一格会是「否」。 这种差异书上一个字都没提, 因为它写的是 MySQL。 第三张表是全课的坐标。 6 个供货商、13 个产品、5 个顾客、5 张订单、11 条订单明细、 4 条产品备注。后面凡是问「筛出来的行数对不对」,都拿这张表当基准。 最后一段讲完全限定的表名。 只查一张表时 products.prod_name 是啰嗦,但第 15 章一联结, 两张表都有 prod_name 这种字段时,不写表名数据库就不知道你说的是谁——那时候它不是啰嗦,是必须。

30 秒实验

  1. 把六张表的字段名都 DESCRIBE 一遍,找出哪些字段允许空、哪些是主键。
  2. 故意在没选库的时候敲一句 SELECT——本课怎么复现这个报错? (提示:SQLite 里没有「没选库」这个状态,想想为什么。)
  3. 用 SHOW CREATE TABLE(MySQL)或查 sqlite_master 的 sql 列,把 products 的建表语句原样打出来, 和你自己写的那句比一比。

常见误区

  1. 连上去就敲 SELECT。没选库会报 No database selected。先 USE,再查表——这是固定的前两步。
  2. 把 -p 和密码贴在一起写。-p密码 能用,但密码会进 shell 历史、进 ps 输出。 只写 -p,让它问。
  3. 以为 DESCRIBE 能看索引。它只给字段和主键,索引要看 SHOW INDEX FROM 表名;。 两件事,两条命令。
自测三问(点开对答案) 1. 连接命令里 -h、-u、-p 各是什么?为什么 -p 后面常常不写密码? —— 主机、用户、密码。 不写密码是为了不让它进 shell 历史记录和进程列表,回车后单独提示输入更安全。 2. 为什么连上之后直接 SELECT 会报 No database selected? —— 因为服务器上有很多库,你还没说清在哪一个库里找表。USE 库名 之后才有默认库。 SQLite 一个文件一个库,就不存在这个状态。 3. 到一个陌生库,最先该敲哪三句? —— SHOW DATABASES(或看有哪些库)、SHOW TABLES(有哪些表)、DESCRIBE 表名(表结构)。 SQLite 对应 sqlite_master 与 PRAGMA table_info。

地形摸清了,下一章开始真正的检索:SELECT 怎么挑列——单列、多列、所有列、不重复的值、 只取前几行,还有完全限定的表名什么时候必须写。

相关笔记