CategoryResourceRepost/极客时间专栏/MySQL 必知必会/实践篇/03 | 表:怎么创建和修改表?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

492 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="03 | 表:怎么创建和修改表?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/7d/4f/7d74a01588b6a686fa489e7b7d1c144f.mp3"></audio>
你好,我是朱晓峰。今天,我们来聊一聊怎么创建和修改数据表。
创建和修改数据表,是数据存储过程中的重要一环。我们不仅需要把表创建出来,还需要正确地设置限定条件,这样才能确保数据的一致性和完整性。同时,表中的数据会随着业务需求的变化而变化,添加和修改相应的字段也是常见的操作。这节课,我们就来学习下具体的方法。
在我们的超市项目里客户经常需要进货这就需要在MySQL数据库里面创建一个表来管理进货相关的数据。我们先看看这个表里有什么内容。
假设这个表叫做进货单头表importhead如下图所示
<img src="https://static001.geekbang.org/resource/image/83/ff/83c593cb7679ed5f99c29d937712c8ff.jpg" alt="">
这里的1、2、3表示门店的3种进货方式分别是配送中心配送、门店采买和供货商直供。
其中“1配送中心配送”是标准进货方式。因为超市是连锁经营为了确保商品质量和品类一致超过9成的门店进货是通过配送中心进行配送的。因此我们希望这个字段的值能够默认是1这样一来除非有特别的指定否则门店进货单的进货方式就自动设置成“1”了。
现在客户需要一个类似的表来存储进货数据而且进货方式还有3个可能的取值范围需要设置默认值那么应该怎么创建这个表呢另外创建好表以后又该怎么进行修改呢
## 如何创建数据表?
首先我们要知道MySQL创建表的语法结构
```
CREATE TABLE &lt;表名&gt;
{
字段名1 数据类型 [字段级别约束] [默认值]
字段名2 数据类型 [字段级别约束] [默认值]
......
[表级别约束]
};
```
在这里,我们通过定义表名、表中的字段、表的属性等,把一张表创建出来。
你可能注意到了在MySQL创建表的语法结构里面有一个词叫做“约束”。**“约束”限定了表中数据应该满足的条件**。MySQL会根据这些限定条件对表的操作进行监控阻止破坏约束条件的操作执行并提示错误从而确保表中数据的唯一性、合法性和完整性。这是创建表时不可缺少的一部分。
下面我来带你创建刚刚提到的进货单表。需要注意的是,这里我们需要定义默认值,也就是要定义默认值约束,除此之外,还有很多种约束,一会儿我再细讲。
我们先来看基本的数据表创建流程,创建代码如下:
```
CREATE TABLE demo.importhead
(
listnumber INT,
supplierid INT,
stocknumber INT,
--我们在字段importype定义为INT类型的后面按照MySQL创建表的语法加了默认值1。
importtype INT DEFAULT 1,
quantity DECIMAL(10,3),
importvalue DECIMAL(10,2),
recorder INT,
recordingdate DATETIME
);
```
运行这个SQL语句表demo.importhead就按照我们的要求被创建出来了。
在创建表的时候字段名称要避开MySQL的[系统关键字](https://dev.mysql.com/doc/refman/8.0/en/keywords.html#keywords-removed-in-current-series)原因是MySQL系统保留的关键字都有特定的含义如果作为字段名称出现在SQL语句中MySQL会把这个字段名称理解为系统关键字从而导致SQL语句无法正常运行。比如刚刚我们把进货金额设置为“importvalue”而不是“value”就是因为“value”是MySQL的系统关键字。
好了现在我们尝试往刚刚创建的表里插入一条记录来验证一下对字段“importtype”定义的默认值约束是否起了作用。
```
INSERT INTO demo.importhead
(
listnumber,
supplierid,
stocknumber,
-- 这里我们没有插入字段importtype的值
quantity,
importvalue,
recorder,
recordingdate
)
VALUES
(
3456,
1,
1,
10,
100,
1,
'2020-12-10'
);
```
插入完成后,我们来查询一下表的内容:
```
SELECT *
FROM demo.importhead
```
运行结果如下:
```
mysql&gt; select * from demo.importhead;
+------------+------------+-------------+------------+----------+-------------+----------+---------------------+
| listnumber | supplierid | stocknumber | importtype | quantity | importvalue | recorder | recordingdate |
+------------+------------+-------------+------------+----------+-------------+----------+---------------------+
| 1234 | 1 | 1 | 1 | 10.000 | 100.00 | 1 | 2020-12-10 00:00:00 |
| 2345 | 1 | 1 | 2 | 20.000 | 2000.00 | 1 | 2020-12-10 00:00:00 |
| 3456 | 1 | 1 | 1 | 20.000 | 2000.00 | 1 | 2020-12-10 00:00:00 |
+------------+------------+-------------+------------+----------+-------------+----------+---------------------+
3 rows in set (0.00 sec)
```
你会发现字段importtype的值已经是1了。这样通过在创建表的时候设置默认值我们就实现了将字段的默认值定义为1的目的。
到这里,表就被创建出来了。
### 都有哪些约束?
刚刚这种给字段设置默认值的做法,就是默认约束。设置了默认约束,插入数据的时候,如果不明确给字段赋值,那么系统会把设置的默认值自动赋值给字段。
除了默认约束,还有主键约束、外键约束、非空约束、唯一性约束和自增约束。
我们在[上节课](https://time.geekbang.org/column/article/350470)里学的主键,其实就是主键约束,我就不多说了。外键约束涉及表与表之间的关联,以及确保表的数据一致性的问题,内容比较多,后面我在讲“关联表”的时候,再给你具体解释。
现在,我来重点给你介绍一下非空约束、唯一性约束和自增约束。
**1.非空约束**
非空约束表示字段值不能为空,如果创建表的时候,指明某个字段非空,那么添加数据的时候,这个字段必须有值,否则系统就会提示错误。
**2.唯一性约束**
唯一性约束表示这个字段的值不能重复,否则系统会提示错误。跟主键约束相比,唯一性约束要更加弱一些。
在一个表中我们可以指定多个字段满足唯一性约束而主键约束则只能有一个这也是MySQL系统决定的。另外**满足主键约束的字段,自动满足非空约束,但是满足唯一性约束的字段,则可以是空值**。
为了方便你理解我来举个例子。比如我们有个商品信息表goodsmaster如下所示
<img src="https://static001.geekbang.org/resource/image/5f/93/5f73f86c51f7b259fef9d52eaf5da893.jpg" alt="">
barcode代表条码goodsname代表名称。为了防止条码重复我们可以定义字段“barcode”满足唯一性约束。这样一来条码就不能重复但是可以为空而且只能有一条记录条码为空。
同样道理为了防止名称重复我们也可以定义字段“goodsname”满足唯一性约束。但是由于无论名称和条码都可能重用或者可能为空都不适合做主键。因此对这个表来说可以添加一个满足唯一性要求的新字段来做主键。
**3.自增约束**
自增约束可以让MySQL自动给字段赋值且保证不会重复非常有用只是不容易用好。所以我借助一个例子来给你具体讲一讲。
假如我们有这样一个商品信息表:
<img src="https://static001.geekbang.org/resource/image/52/c2/524bfc84ab3555283dd981a14f2a06c2.jpg" alt="">
从这个表中我们可以看到barcode、goodsname和price都不能确保唯一性所以没有任何一个字段可以做主键因此我们可以自己添加一个字段itemnumber并且每次添加一条数据的时候要给值增加1。怎么实现呢我们就可以通过定义自增约束的方式让系统自动帮我们赋值从而满足唯一性这样就可以做主键了。
<img src="https://static001.geekbang.org/resource/image/e0/b1/e004230d1b626e17c3822c678cb1e5b1.jpg" alt="">
这里有2个问题需要你注意一下。
第一在数据表中只有整数类型的字段包括TINYINT、SMALLINT、MEDIUMINT、INT和BIGINT才可以定义自增约束。自增约束的字段每增加一条数据值自动增加1。
第二你可以给自增约束的字段赋值这个时候MySQL会重置自增约束字段的自增基数下次添加数据的时候自动以自增约束字段的最大值加1为新的字段值。
举个例子我们通过Workbench把数据表demo.goodsmaster中的字段itemnumber定义为满足自增约束如下图所示
<img src="https://static001.geekbang.org/resource/image/4b/22/4bb1264e88ee558e51061e0956d13f22.png" alt="">
然后,我们插入一条测试记录:
```
INSERT INTO demo.goodsmaster
(
itemnumber,
barcode,
goodsname,
specification,
unit,
price
)
VALUES
(
-- 指定商品编号为100
100,
'0003',
'测试1',
'',
'个',
10
);
```
运行这条语句之后,查看表的内容,我们得到:
```
mysql&gt; select * from demo.goodsmaster;
+------------+---------+-----------+---------------+------+----+
| itemnumber | barcode | goodsname | specification | unit | price |
+------------+---------+-----------+---------------+------+-------+
| 1 | 0001 | 书 | 16开 | 本 | 89.00 |
| 2 | 0002 | 地图 | NULL | 张 | 9.90 |
| 3 | 0003 | 笔 | 10支 | 包 | 3.00 |
| 100 | 0003 | 测试1 | | 个 | 10.00 |
+------------+---------+-----------+---------------+------+-------+
4 rows in set (0.02 sec)
```
这个时候字段“itemnumber”的值不连续最大值是我们刚刚插入的100。
接着,我们再插入一条数据:
```
INSERT INTO demo.goodsmaster
(
-- 不指定自增字段itemnumber的值
barcode,
goodsname,
specification,
unit,
supplierid,
price
)
VALUES
(
'0004',
'测试2',
'',
'个',
1,
20
);
```
运行这条语句之后,我们再查看表的内容:
```
mysql&gt; select * from demo.goodsmaster;
+------------+---------+-----------+---------------+------+-------+
| itemnumber | barcode | goodsname | specification | unit | price |
+------------+---------+-----------+---------------+------+-------+
| 1 | 0001 | 书 | 16开 | 本 | 89.00 |
| 2 | 0002 | 地图 | NULL | 张 | 9.90 |
| 3 | 0003 | 笔 | 10支 | 包 | 3.00 |
| 100 | 0003 | 测试1 | | 个 | 10.00 |
| 101 | 0004 | 测试2 | | 个 | 20.00 |
+------------+---------+-----------+---------------+------+-------+
5 rows in set (0.00 sec)
```
可以看到系统自动给自增字段“itemnumber”在最大值的基础之上加了1赋值为101。
好了,到这里,我们就学会了创建表和定义约束的方法。约束要根据业务需要定义在相应的字段上,这样才能保证数据是准确的,你一定要注意它的使用方法。
## 如何修改表?
创建完表以后,我们经常还需要修改表,下面我们就来学习下修改表的方法。
在咱们的超市项目中当我们创建新表的时候会出现这样的情况我们前面创建的进货单表是用来存储进货数据的。但是我们还要创建一个进货单历史表importheadhist用来存储验收过的进货数据。这个表的结构跟进货单表类似只是多了2个字段分别是验收人confirmer和验收时间confirmdate。针对这种情况我们很容易想到可以通过复制表结构然后在这个基础上通过修改表结构来创建新的表。具体怎么实现呢接下来我就给你讲解一下。
首先,我们要把原来的表结构复制一下,代码如下:
```
CREATE TABLE demo.importheadhist
LIKE demo.importhead;
```
运行这个语句之后一个跟demo.importhead有相同表结构的空表demo.importheadhist就被创建出来了。
这个新创建出来的表,还不是我们需要的表,我们需要对这个表进行修改,通过添加字段和修改字段,来获得我们需要的“进货单历史表”。
### 添加字段
你可能会想到我们可以通过Workbench用可视化操作来修改表的结构如下图所示
<img src="https://static001.geekbang.org/resource/image/53/3f/537d01d3c33f8c9f804056e7795d1e3f.png" alt="">
这样当然没问题,但是我想给你讲一个更方便灵活的方式:**用SQL语句来修改表的结构**。
现在我要给这个新的表增加2个字段confirmer和confirmdate就可以用下面的代码
```
mysql&gt; ALTER TABLE demo.importheadhist
-&gt; ADD confirmer INT; -- 添加一个字段confirmer类型INT
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql&gt; ALTER TABLE demo.importheadhist
-&gt; ADD confirmdate DATETIME; -- 添加一个字段confirmdate类型是DATETIME
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
```
运行这个SQL语句查看表的结构你会发现在字段的最后多了两个字段
- “confirmer”数据类型是INT
- “confirmdate"类型是DATETIME。
我们来查看一下表结构:
```
mysql&gt; DESCRIBE demo.importheadhist;
+----------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------+------+-----+---------+-------+
| listnumber | int | NO | PRI | NULL | |
| supplierid | int | NO | | NULL | |
| stocknumber | int | NO | | NULL | |
| importtype | int | YES | | 1 | |
| quantity | decimal(10,3) | YES | | NULL | |
| importvalue | decimal(10,2) | YES | | NULL | |
| recorder | int | YES | | NULL | |
| recordingdate | datetime | YES | | NULL | |
| confirmer | int | YES | | NULL | |
| confirmdate | datetime | YES | | NULL | |
+----------------+---------------+------+-----+---------+-------+
10 rows in set (0.02 sec)
```
这样通过简单增加2个字段我们就获得了进货单历史表。
### 修改字段
除了添加字段我们可能还要修改字段比如我们要把字段名称“quantity”改成“importquantity”并且把字段类型改为DOUBLE该怎么操作呢
我们可以通过修改表结构语句ALTER TABLE来修改字段
```
mysql&gt; ALTER TABLE demo.importheadhist
-&gt; CHANGE quantity importquantity DOUBLE;
Query OK, 0 rows affected (0.15 sec)
Records: 0 Duplicates: 0 Warnings: 0
```
运行这个SQL语句查看表的结构我们会得到下面的结果
```
mysql&gt; DESCRIBE demo.importheadhist;
+----------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------+------+-----+---------+-------+
| listnumber | int | NO | PRI | NULL | |
| supplierid | int | NO | | NULL | |
| stocknumber | int | NO | | NULL | |
| importtype | int | YES | | 1 | |
| importquantity | double | YES | | NULL | |
| importvalue | decimal(10,2) | YES | | NULL | |
| recorder | int | YES | | NULL | |
| recordingdate | datetime | YES | | NULL | |
| confirmer | int | YES | | NULL | |
| confirmdate | datetime | YES | | NULL | |
+----------------+---------------+------+-----+---------+-------+
10 rows in set (0.02 sec)
```
可以看到,字段名称和字段类型全部都改过来了。
如果你不想改变字段名称只想改变字段类型例如把字段“importquantity”类型改成DECIMAL(10,3),你可以这样写:
```
ALTER TABLE demo.importheadhist
MODIFY importquantity DECIMAL(10,3);
```
运行SQL语句查看表结构你会发现已经改过来了。
```
mysql&gt; DESCRIBE demo.importheadhist;
+----------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------+------+-----+---------+-------+
| listnumber | int | NO | PRI | NULL | |
| supplierid | int | NO | | NULL | |
| stocknumber | int | NO | | NULL | |
| importtype | int | YES | | 1 | |
| importquantity | decimal(10,3) | YES | | NULL | |
| importvalue | decimal(10,2) | YES | | NULL | |
| recorder | int | YES | | NULL | |
| recordingdate | datetime | YES | | NULL | |
| confirmer | int | YES | | NULL | |
| confirmdate | datetime | YES | | NULL | |
+----------------+---------------+------+-----+---------+-------+
10 rows in set (0.02 sec)
```
我们还可以通过SQL语句**向表中添加一个字段**,我们甚至可以指定添加字段在表中的位置。
比如说在字段supplierid之后添加一个字段suppliername数据类型是TEXT。我们可以这样写SQL语句
```
ALTER TABLE demo.importheadhist
ADD suppliername TEXT AFTER supplierid;
```
运行SQL语句查看表结构
```
mysql&gt; DESCRIBE demo.importheadhist;
+----------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------+------+-----+---------+-------+
| listnumber | int | NO | PRI | NULL | |
| supplierid | int | NO | | NULL | |
| suppliername | text | YES | | NULL | |
| stocknumber | int | NO | | NULL | |
| importtype | int | YES | | 1 | |
| importquantity | decimal(10,3) | YES | | NULL | |
| importvalue | decimal(10,2) | YES | | NULL | |
| recorder | int | YES | | NULL | |
| recordingdate | datetime | YES | | NULL | |
| confirmer | int | YES | | NULL | |
| confirmdate | datetime | YES | | NULL | |
+----------------+---------------+------+-----+---------+-------+
11 rows in set (0.02 sec)
```
到这里,我们就完成了修改字段在表中位置的操作。
## 总结
这节课,我们学习了创建和修改数据表的具体方法。在讲创建表时,我讲到了一个重要的概念,就是约束,包括默认约束、非空约束、唯一性约束和自增约束等。
- 默认值约束:就是给字段设置一个默认值。
- 非空约束:就是声明字段不能为空值。
- 唯一性约束:就是声明字段不能重复。
- 自增约束就是声明字段值能够自动加1且不会重复。
在修改表时,我们可以通过修改已经存在的表创建新表,也可以通过添加字段、修改字段的方式来修改数据表。
最后我给你汇总了一些常用的创建表的SQL语句你一定要牢记。
```
CREATE TABLE
(
字段名 字段类型 PRIMARY KEY
);
CREATE TABLE
(
字段名 字段类型 NOT NULL
);
CREATE TABLE
(
字段名 字段类型 UNIQUE
);
CREATE TABLE
(
字段名 字段类型 DEFAULT 值
);
-- 这里要注意自增类型的条件,字段类型必须是整数类型。
CREATE TABLE
(
字段名 字段类型 AUTO_INCREMENT
);
-- 在一个已经存在的表基础上,创建一个新表
CREATE demo.importheadhist LIKE demo.importhead;
-- 修改表的相关语句
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 数据类型;
ALTER TABLE 表名 ADD COLUMN 字段名 字段类型 FIRST|AFTER 字段名;
ALTER TABLE 表名 MODIFY 字段名 字段类型 FIRST|AFTER 字段名;
```
对于初学者来说掌握了今天的内容就足够对数据表进行操作了。不过MySQL支持的数据表操作不只这些我来举几个简单的小例子你可以了解一下有个印象。
比如,你可以在表一级指定表的存储引擎:
```
ALTER TABLE 表名 ENGINE=INNODB;
```
你还可以通过指定关键字AUTO_EXTENDSIZE来指定存储文件自增空间的大小从而提高存储空间的利用率。
在MySQL 8.0.23之后的版本中你甚至还可以通过INVISIBLE关键字使字段不可见但却可以使用。
如果你想了解更多有关数据表的操作,我也给你提供两份资料:[MySQL创建表文档](https://dev.mysql.com/doc/refman/8.0/en/create-table.html)和[MySQL修改表文档](https://dev.mysql.com/doc/refman/8.0/en/alter-table.html)。这些都是MySQL的官方文档相信会对你有所帮助。
## 思考题
请你写一个SQL语句将表demo.goodsmaster中的字段“salesprice”改成不能重复并且不能为空。
欢迎在留言区写下你的思考和答案,我们一起交流讨论。如果你觉得今天的内容对你有所帮助,欢迎你把它分享给你的朋友或同事,我们下节课见。