conanan's blog conanan's blog
首页
关于
  • 分类
  • 标签
  • 归档
  • Java
  • Java Web
  • 工具

    • Maven
  • MySQL
  • Redis
  • Git
  • Vim
  • Nginx
  • Docker
GitHub

Evan Xu

前端界的小学生
首页
关于
  • 分类
  • 标签
  • 归档
  • Java
  • Java Web
  • 工具

    • Maven
  • MySQL
  • Redis
  • Git
  • Vim
  • Nginx
  • Docker
GitHub
  • 基础

    • 数据库简介
    • SQL 介绍
    • 列数据类型 🔥
    • DDL—数据库
    • DDL—表&列 🔥
      • 表—展示当前数据库中的表 🔥
      • 表—创建表 🔥
        • 语法
        • 示例
      • 表—删除表 🔥
      • 表—查看表结构 🔥
      • 表—查看表的定义信息 🔥
      • 表—查看表详细状态信息 🔥
      • 表—没有选择当前数据库时对表的操作 🔥
      • 表—修改表名 🔥
        • 方式一:
        • 方式二:
      • 表—复制表结构 🔥
      • 表—修改表的字符集 🔥
      • ===============
      • 列—增加列 🔥
        • 语法
        • 增加列到特定位置
      • 列—删除列 🔥
      • 列—修改列信息 🔥
        • 修改列的信息
        • 修改列排列位置
      • 列—一条语句中包含多个修改操作 🔥
      • ===============
      • 列的属性(约束)
        • 主键 🔥
        • UNIQUE 属性 🔥
        • 主键和 UNIQUE 约束的区别
        • NOT NULL 属性 🔥
        • 默认值 🔥
        • 外键
        • AUTO_INCREMENT 属性
        • 列的注释
        • 影响展示外观的 ZEROFILL 属性
        • 一个列同时具有多个属性
        • 查看表结构时的列属性
      • 标识符的命名
    • DML 🔥
    • DQL 🔥
    • 复杂查询 🔥
    • 集合运算 🔥
    • 存储程序
  • 高级

  • 运维

  • 练习

  • MySQL
  • 基础
conanan
2021-01-16

DDL—表&列 🔥

# DDL—表&列

DDL 无需 commit

# 表—展示当前数据库中的表 🔥

SHOW TABLES;
1

当前数据库是demo,然后用上述语句查看下demo数据库中都有哪些表:

mysql> SHOW TABLES;
Empty set (0.00 sec)

mysql>
1
2
3
4

# 表—创建表 🔥

# 语法

 CREATE TABLE [IF NOT EXISTS] 表名 (
     列名1    数据类型    [列的属性],
     列名2    数据类型    [列的属性],
     ...
     列名n    数据类型    [列的属性],
     PRIMARY KEY (列名)
 ) COMMENT '表的注释信息';

-- 约束可以在定义列的时候进行设置,也可以在语句的末尾进行设置。但是NOT NULL约束只能以列为单位进行设置
1
2
3
4
5
6
7
8
9
  • 在CREATE TABLE后写清楚我们要创建的表的名称。
  • 然后在小括号()中定义上这个表的各个列的信息,包括列的名称、列的数据类型,如果有需要的话也可以定义这个列的属性(列的属性用中括号[]引起来的意思就是这部分是可选的,也就是可有可无的)。
  • 列名、数据类型、列的属性之间用空白字符分开就好,然后各个列的信息之间用逗号,分隔开。
  • 如果创建一个已经存在的表的话是会报错的,可以加入IF NOT EXISTS语句

# 示例

mysql> CREATE TABLE first_table (
    ->     first_column INT,
    ->     second_column VARCHAR(100)
    -> ) COMMENT '第一个表';
Query OK, 0 rows affected (0.02 sec)

mysql>
1
2
3
4
5
6
7

输出Query OK, 0 rows affected (0.02 sec)意味着创建成功了,并且耗时 0.02 秒。

有了创建first_table的经验,我们就可以着手用MySQL把之前提到的学生基本信息表和成绩表给创建出来了,先把学生基本信息表搬下来看看:

学生基本信息表

学号 姓名 性别 身份证号 学院 专业 入学时间
20180101 杜子腾 男 158177199901044792 计算机学院 计算机科学与工程 2018/9/1
20180102 杜琦燕 女 151008199801178529 计算机学院 计算机科学与工程 2018/9/1
20180103 范统 男 17156319980116959X 计算机学院 软件工程 2018/9/1
20180104 史珍香 女 141992199701078600 计算机学院 软件工程 2018/9/1

很显然,这个表有学号、姓名、性别、身份证号、学院、专业、入学时间这几个列,其中的学号是整数类型的,入学时间是日期类型的,由于身份证号是固定的 18 位,我们可以把身份证号这一列定义成固定长度的字符串类型,性别一列只能填男或女,所以我们这里把它定义为ENUM类型的,其余各个列都是变长的字符串类型。看一下创建学生基本信息表的语句:

CREATE TABLE student_info (
    number INT,
    name VARCHAR(5),
    sex ENUM('男', '女'),
    id_number CHAR(18),
    department VARCHAR(30),
    major VARCHAR(30),
    enrollment_time DATE
) COMMENT '学生基本信息表';
1
2
3
4
5
6
7
8
9

然后再看一下学生成绩表:

学号 科目 成绩
20180101 母猪的产后护理 78
20180101 论萨达姆的战争准备 88
20180102 母猪的产后护理 100
20180102 论萨达姆的战争准备 98
20180103 母猪的产后护理 59
20180103 论萨达姆的战争准备 61
20180104 母猪的产后护理 55
20180104 论萨达姆的战争准备 46

这个表有学号、科目、成绩这几个列,学号和成绩是整数类型的,科目是字符串类型的,所以我们可以这样写建表语句:

CREATE TABLE student_score (
    number INT,
    subject VARCHAR(30),
    score TINYINT
) COMMENT '学生成绩表';
1
2
3
4
5

待这几个表创建成功之后,我们使用SHOW TABLES语句看一下当前数据库中有哪些表:

mysql> SHOW TABLES;
+---------------------+
| Tables_in_demo |
+---------------------+
| first_table         |
| student_info        |
| student_score       |
+---------------------+
3 rows in set (0.01 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
DROP TABLE IF EXISTS `player`;
CREATE TABLE `player`  (
    `player_id` int(11) NOT NULL AUTO_INCREMENT,
    `team_id` int(11) NOT NULL,
    `player_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
    `height` float(3, 2) NULL DEFAULT 0.00,
    PRIMARY KEY (`player_id`) USING BTREE,
    UNIQUE INDEX `player_name`(`player_name`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- 其中 player_name 字段的字符集是 utf8(推荐utf-8mb4),排序规则是 utf8_general_ci,代表对大小写不敏感,如果设置为utf8_bin,代表对大小写敏感,还有许多其他排序规则这里不进行介绍。
1
2
3
4
5
6
7
8
9
10

# 表—删除表 🔥

DROP TABLE [IF EXISTS] 表1, 表2, ..., 表n;
1
mysql> DROP TABLE first_table;
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW TABLES;
+---------------------+
| Tables_in_demo |
+---------------------+
| student_info        |
| student_score       |
+---------------------+
2 rows in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13

如果我们尝试删除某个不存在的表的话会报错,可以加入IF EXISTS语句

# 表—查看表结构 🔥

DESC 表名;
DESCRIBE 表名;
EXPLAIN 表名;
SHOW COLUMNS FROM 表名;
SHOW FIELDS FROM 表名;
1
2
3
4
5

比如我们看一下student_info这个表的结构:

mysql> DESC student_info;
+-----------------+-------------------+------+-----+---------+-------+
| Field           | Type              | Null | Key | Default | Extra |
+-----------------+-------------------+------+-----+---------+-------+
| number          | int(11)           | YES  |     | NULL    |       |
| name            | varchar(5)        | YES  |     | NULL    |       |
| sex             | enum('男','女')   | YES  |     | NULL    |       |
| id_number       | char(18)          | YES  |     | NULL    |       |
| department      | varchar(30)       | YES  |     | NULL    |       |
| major           | varchar(30)       | YES  |     | NULL    |       |
| enrollment_time | date              | YES  |     | NULL    |       |
+-----------------+-------------------+------+-----+---------+-------+
7 rows in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

可以看到,这个student_info表的各个列的名称、类型和属性就都展示出来了。

# 表—查看表的定义信息 🔥

SHOW CREATE TABLE 表名;
1

比如:

mysql> SHOW CREATE TABLE student_info;
+--------------+------------------------------------------+
| Table        | Create Table
+--------------+------------------------------------------+
| student_info | CREATE TABLE `student_info` (
  `number` int(11) DEFAULT NULL,
  `name` varchar(5) DEFAULT NULL,
  `sex` enum('男','女') DEFAULT NULL,
  `id_number` char(18) DEFAULT NULL,
  `department` varchar(30) DEFAULT NULL,
  `major` varchar(30) DEFAULT NULL,
  `enrollment_time` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='学生基本信息表'          |
+--------------+-------------------------------------------+
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

由于这行数据太长了,所以输出效果并不是很好,我们可以把原来用于标记语句结束的分号;改为\G,以垂直的方式展示每一列数据的效果可能好点:

mysql> SHOW CREATE TABLE student_info\G
*************************** 1. row ***************************
       Table: student_info
Create Table: CREATE TABLE `student_info` (
  `number` int(11) DEFAULT NULL,
  `name` varchar(5) DEFAULT NULL,
  `sex` enum('男','女') DEFAULT NULL,
  `id_number` char(18) DEFAULT NULL,
  `department` varchar(30) DEFAULT NULL,
  `major` varchar(30) DEFAULT NULL,
  `enrollment_time` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='学生基本信息表'
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

可以看到,使用SHOW CREATE TABLE这个语句展示出来的表结构就是我们平时创建表的语句

# 表—查看表详细状态信息 🔥

show table status; -- 所有表
1
+-------------+------+-------+----------+----+--------------+-----------+---------------+------------+---------+--------------+-------------------+-------------------+----------+------------------+--------+--------------+-------+
|Name         |Engine|Version|Row_format|Rows|Avg_row_length|Data_length|Max_data_length|Index_length|Data_free|Auto_increment|Create_time        |Update_time        |Check_time|Collation         |Checksum|Create_options|Comment|
+-------------+------+-------+----------+----+--------------+-----------+---------------+------------+---------+--------------+-------------------+-------------------+----------+------------------+--------+--------------+-------+
|a            |InnoDB|10     |Dynamic   |4   |4096          |16384      |0              |0           |0        |NULL          |2021-01-16 15:25:43|2021-01-16 15:26:44|NULL      |utf8mb4_general_ci|NULL    |              |       |
|article      |InnoDB|10     |Dynamic   |0   |0             |16384      |0              |0           |0        |NULL          |2020-12-20 23:48:02|NULL               |NULL      |utf8mb4_general_ci|NULL    |              |       |
|b            |InnoDB|10     |Dynamic   |4   |4096          |16384      |0              |0           |0        |NULL          |2021-01-16 15:27:30|2021-01-16 15:30:23|NULL      |utf8mb4_general_ci|NULL    |              |       |
|customer     |InnoDB|10     |Dynamic   |1   |16384         |16384      |0              |0           |0        |2             |2020-12-20 23:48:02|2020-12-21 00:23:52|NULL      |utf8mb4_general_ci|NULL    |              |       |
|link_man     |InnoDB|10     |Dynamic   |1   |16384         |16384      |0              |16384       |0        |2             |2020-12-20 23:48:03|2020-12-21 00:23:52|NULL      |utf8mb4_general_ci|NULL    |              |       |
|score        |InnoDB|10     |Dynamic   |8   |2048          |16384      |0              |0           |0        |9             |2021-01-16 13:08:42|2021-01-16 13:13:11|NULL      |utf8mb4_general_ci|NULL    |              |成绩表    |
|sys_role     |InnoDB|10     |Dynamic   |1   |16384         |16384      |0              |0           |0        |6             |2020-12-20 23:48:02|2020-12-21 00:12:20|NULL      |utf8mb4_general_ci|NULL    |              |       |
|sys_user     |InnoDB|10     |Dynamic   |3   |5461          |16384      |0              |0           |0        |8             |2020-12-20 23:48:02|2021-01-16 01:28:21|NULL      |utf8mb4_general_ci|NULL    |              |       |
|sys_user_role|InnoDB|10     |Dynamic   |1   |16384         |16384      |0              |16384       |0        |NULL          |2020-12-20 23:48:03|2020-12-21 00:13:49|NULL      |utf8mb4_general_ci|NULL    |              |       |
|tlm          |InnoDB|10     |Dynamic   |3   |5461          |16384      |0              |0           |0        |4             |2020-12-21 10:53:30|2020-12-21 11:02:33|NULL      |utf8mb4_general_ci|NULL    |              |       |
|user         |InnoDB|10     |Dynamic   |0   |0             |16384      |0              |0           |0        |NULL          |2020-12-20 23:48:03|NULL               |NULL      |utf8mb4_general_ci|NULL    |              |       |
+-------------+------+-------+----------+----+--------------+-----------+---------------+------------+---------+--------------+-------------------+-------------------+----------+------------------+--------+--------------+-------+

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
show table status where Name = 'a';
1
+---------------+-------------------+
|Name           |a                  |
+---------------+-------------------+
|Engine         |InnoDB             |
+---------------+-------------------+
|Version        |10                 |
+---------------+-------------------+
|Row_format     |Dynamic            |
+---------------+-------------------+
|Rows           |4                  |
+---------------+-------------------+
|Avg_row_length |4096               |
+---------------+-------------------+
|Data_length    |16384              |
+---------------+-------------------+
|Max_data_length|0                  |
+---------------+-------------------+
|Index_length   |0                  |
+---------------+-------------------+
|Data_free      |0                  |
+---------------+-------------------+
|Auto_increment |NULL               |
+---------------+-------------------+
|Create_time    |2021-01-16 15:25:43|
+---------------+-------------------+
|Update_time    |2021-01-16 15:26:44|
+---------------+-------------------+
|Check_time     |NULL               |
+---------------+-------------------+
|Collation      |utf8mb4_general_ci |
+---------------+-------------------+
|Checksum       |NULL               |
+---------------+-------------------+
|Create_options |                   |
+---------------+-------------------+
|Comment        |                   |
+---------------+-------------------+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 表—没有选择当前数据库时对表的操作 🔥

有时候我们并没有使用USE语句来选择当前数据库,或者在一条语句中遇到的表分散在不同的数据库中,如果我们想在语句中使用这些表,那么就必须显式的指定这些表所属的数据库了。比如不管当前数据库是不是demo,我们都可以调用这个语句来展示数据库demo里边的表:

mysql> SHOW TABLES FROM demo;
+---------------------+
| Tables_in_demo |
+---------------------+
| first_table         |
| student_info        |
| student_score       |
+---------------------+
3 rows in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11

其他地方如果使用到表名的话,需要显式指定这个表所属的数据库,指明方式是这样的:

数据库名.表名
1

比方说我们想查看demo数据库下first_table表的结构,但是又没有使用USE demo语句指定当前数据库,此时可以这样写语句:

SHOW CREATE TABLE demo.first_table\G
1

# 表—修改表名 🔥

# 方式一:

ALTER TABLE 旧表名 RENAME TO 新表名;
1

我们把first_table表的名称修改为first_table1(当前数据库为demo):

mysql> ALTER TABLE first_table RENAME TO first_table1;
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW TABLES;
+---------------------+
| Tables_in_xiaohaizi |
+---------------------+
| first_table1        |
| student_info        |
| student_score       |
+---------------------+
3 rows in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

通过SHOW TABLES命令可以看到已经改名成功了。

# 方式二:

RENAME TABLE 旧表名1 TO 新表名1, 旧表名2 TO 新表名2, ... 旧表名n TO 新表名n;
1

这种改名方式的牛逼之处就是它可以在一条语句中修改多个表的名称。这里就不举例了,自己测试一下吧。

如果在修改表名的时候指定了数据库名,还可以将该表转移到对应的数据库下,比方说我们先再创建一个数据库demo2:

mysql> CREATE DATABASE demo2;
Query OK, 1 row affected (0.00 sec)

mysql>
1
2
3
4

然后把first_table1表转移到这个demo2数据库下:

mysql> ALTER TABLE first_table1 RENAME TO demo2.first_table1;
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW TABLES FROM demo2;
+-------------------+
| Tables_in_demo2 |
+-------------------+
| first_table1      |
+-------------------+
1 row in set (0.00 sec)

mysql> SHOW TABLES FROM demo;
+---------------------+
| Tables_in_demo |
+---------------------+
| student_info        |
| student_score       |
+---------------------+
2 rows in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

可以看到first_table1就从数据库demo转移到demo2里边了。我们再用修改表名的方式二再把该表转移到demo数据库中,并且将其更名为first_table:

mysql> RENAME TABLE demo2.first_table1 TO demo.first_table;
Query OK, 0 rows affected (0.00 sec)

mysql>
1
2
3
4

# 表—复制表结构 🔥

CREATE TABLE 表名 LIKE 被复制的表名;
1

# 表—修改表的字符集 🔥

ALTER TABLE 表名 CHARACTER  SET UTF8;
1

# ===============

# 列—增加列 🔥

# 语法

我们可以使用下边的语句来增加表中的列:

ALTER TABLE 表名 ADD [COLUMN] 列名 数据类型 [列的属性];
1
ALTER TABLE 表名 ADD /*COLUMN*/(
  列名 列类型 该列所需约束,
    列名 列类型 该列所需约束,
  ...
);
-- MySQL、Oracle、SQL Server中可以不用写COLUMN,PostgreSQL需写上
1
2
3
4
5
6

比如我们向first_table里添加一个名叫third_column的列就可以这么写:

mysql> ALTER TABLE first_table ADD COLUMN third_column CHAR(4) ;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE first_table\G
*************************** 1. row ***************************
       Table: first_table
Create Table: CREATE TABLE `first_table` (
  `first_column` int(11) DEFAULT NULL,
  `second_column` varchar(100) DEFAULT NULL,
  `third_column` char(4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
1 row in set (0.01 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

通过查看表的结构可以看到third_column列已经添加成功了。

# 增加列到特定位置

默认的情况下列都是加到现有列的最后一列后面,我们也可以在添加列的时候指定它的位置,常用的方式如下:

  • 添加到第一列:

    ALTER TABLE 表名 ADD COLUMN 列名 列的类型 [列的属性] FIRST;
    
    1

    让我们把fourth_column插入到第一列:

    mysql> ALTER TABLE first_table ADD COLUMN fourth_column CHAR(4) FIRST;
    Query OK, 0 rows affected (0.04 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> SHOW CREATE TABLE first_table\G
    *************************** 1. row ***************************
       Table: first_table
    Create Table: CREATE TABLE `first_table` (
    `fourth_column` char(4) DEFAULT NULL,
    `first_column` int(11) DEFAULT NULL,
    `second_column` varchar(100) DEFAULT NULL,
    `third_column` char(4) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
    1 row in set (0.01 sec)
    
    mysql>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    看到插入成功了。

  • 添加到指定列的后边:

    ALTER TABLE 表名 ADD COLUMN 列名 列的类型 [列的属性] AFTER 指定列名;
    
    1

    再插入一个fifth_column到first_column后边瞅瞅:

    mysql> ALTER TABLE first_table ADD COLUMN fifth_column CHAR(4) AFTER first_column;
    Query OK, 0 rows affected (0.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> SHOW CREATE TABLE first_table\G
    *************************** 1. row ***************************
           Table: first_table
    Create Table: CREATE TABLE `first_table` (
      `fourth_column` char(4) DEFAULT NULL,
      `first_column` int(11) DEFAULT NULL,
      `fifth_column` char(4) DEFAULT NULL,
      `second_column` varchar(100) DEFAULT NULL,
      `third_column` char(4) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
    1 row in set (0.00 sec)
    
    mysql>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    可以看到fifth_column列就被插到first_column列后边了。

# 列—删除列 🔥

ALTER TABLE 表名 DROP /*COLUMN*/ 列名;
-- MySQL、Oracle可以用 (列名,列名...)来删除多个列
-- MySQL、Oracle、SQL Server中可以不用写COLUMN,PostgreSQL需写上
1
2
3

我们把刚才向first_table里添加几个列都删掉试试:

mysql> ALTER TABLE first_table DROP COLUMN third_column;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE first_table DROP COLUMN fourth_column;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE first_table DROP COLUMN fifth_column;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE first_table\G
*************************** 1. row ***************************
       Table: first_table
Create Table: CREATE TABLE `first_table` (
  `first_column` int(11) DEFAULT NULL,
  `second_column` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

从结果中可以看出third_column、fourth_column、fifth_column这几个列都被删除了。

# 列—修改列信息 🔥

# 修改列的信息

# 方式一(只修改列信息)

ALTER TABLE 表名 MODIFY 列名 新数据类型 [新属性];
1

我们来修改一下first_table表的second_column列,把它的数据类型修改为VARCHAR(2):

mysql> ALTER TABLE first_table MODIFY second_column VARCHAR(2);
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE first_table\G
*************************** 1. row ***************************
       Table: first_table
Create Table: CREATE TABLE `first_table` (
  `first_column` int(11) DEFAULT NULL,
  `second_column` varchar(2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

可以看到second_column的数据类型就已经被修改为VARCHAR(2)了。不过在修改列信息的时候需要注意:修改后的数据类型和属性一定要兼容表中现有的数据!比方说原先first_table表的类型是VARCHAR(100),该类型最多能存储 100 个字符,如果表中的某条记录的second_column列值为'aaa',也就是占用了 3 个字符,而此时我们尝试使用上边的语句将second_column列的数据类型修改为VARCHAR(2),那么此时就会报错,因为VARCHAR(2)并不能存储 3 个字符。

# 方式二(顺便修改列名)

ALTER TABLE 表名 CHANGE 旧列名 新列名 新数据类型 [新属性];
1

可以看到这种修改方式需要我们填两个列名,也就是说在修改数据类型和属性的同时也可以修改列名!比如我们修改second_column的列名为second_column1:

mysql> ALTER TABLE first_table CHANGE second_column second_column1 VARCHAR(2)\G
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE first_table\G
*************************** 1. row ***************************
       Table: first_table
Create Table: CREATE TABLE `first_table` (
  `first_column` int(11) DEFAULT NULL,
  `second_column1` varchar(2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

可以看到结果中second_column的列名已经被修改为了second_column1,不过我们并没有改动该列的数据类型和属性,所以直接把旧的数据类型和属性抄过来就好了。不过在修改列信息的时候需要注意:修改后的数据类型和属性一定要兼容表中现有的数据!

# 方式三(仅修改列名)

ALTER TABLE player RENAME COLUMN age to player_age -- RENAME也可以
1

# 修改列排列位置

如果我们觉得当前列的顺序有问题的话,可以使用下边这几条语句进行修改:

  1. 将列设为表的第一列:

    ALTER TABLE 表名 MODIFY 列名 列的类型 列的属性 FIRST;
    
    1

    先看一下现在表first_table的各个列的排列顺序:

    mysql> SHOW CREATE TABLE first_table\G
    *************************** 1. row ***************************
           Table: first_table
    Create Table: CREATE TABLE `first_table` (
      `first_column` int(11) DEFAULT NULL,
      `second_column1` varchar(2) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
    1 row in set (0.00 sec)
    
    mysql>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    可以看到,列的顺序依次是:first_column、second_column1。现在我们想把second_column放在第一列可以这么写:

    mysql> ALTER TABLE first_table MODIFY second_column1 VARCHAR(2) FIRST;
    Query OK, 0 rows affected (0.02 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> SHOW CREATE TABLE first_table\G
    *************************** 1. row ***************************
           Table: first_table
    Create Table: CREATE TABLE `first_table` (
      `second_column1` varchar(2) DEFAULT NULL,
      `first_column` int(11) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
    1 row in set (0.00 sec)
    
    mysql>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    看到second_column1已经成为第一列了!

  2. 将列放到指定列的后边:

    ALTER TABLE 表名 MODIFY 列名 列的类型 列的属性 AFTER 指定列名;
    
    1

    比方说我们想把second_column1再放到first_column后边可以这么写:

    mysql> ALTER TABLE first_table MODIFY second_column1 VARCHAR(2) AFTER first_column;
    Query OK, 0 rows affected (0.03 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> SHOW CREATE TABLE first_table\G
    *************************** 1. row ***************************
           Table: first_table
    Create Table: CREATE TABLE `first_table` (
      `first_column` int(11) DEFAULT NULL,
      `second_column1` varchar(2) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='第一个表'
    1 row in set (0.00 sec)
    
    mysql>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

# 列—一条语句中包含多个修改操作 🔥

如果对同一个表有多个修改操作的话,我们可以把它们放到一条语句中执行,就像这样:

ALTER TABLE 表名 操作1, 操作2, ..., 操作n;
1

上边我们在演示删除列操作的时候用三条语句连着删了third_column、fourth_column和fifth_column这三个列,其实这三条语句可以合并为一条:

ALTER TABLE first_table DROP COLUMN third_column, DROP COLUMN fourth_column, DROP COLUMN fifth_column;
1

这样人敲的语句也少了,服务器也不用分多次执行从而效率也高了,何乐而不为呢?

# ===============

# 列的属性(约束)

# 主键 🔥

有时候在我们的表里可以通过某个列或者某些列确定唯一的一条记录,我们就可以把这个列或者这些列称为候选键。比如在学生信息表student_info中,只要我们知道某个学生的学号,就可以确定一个唯一的学生信息,也就是一条记录。当然,我们也可以通过身份证号来确定唯一的一条学生信息记录,所以学号和身份证号都可以作为学生信息表的候选键。在学生成绩表student_score中,我们可以通过学号和科目这两个列的组合来确定唯一的一条成绩记录,所以学号、科目这两个列的组合可以作为学生成绩表的候选键。

一个表可能有多个候选键,我们可以选择一个候选键作为表的主键。一个表最多只能有一个主键,主键的值不能重复,通过主键可以找到唯一的一条记录。如果我们的表中有定义主键的需求可以选用下边这两种方式之一来指定主键:

  1. 如果主键只是单个列的话,可以直接在该列后声明PRIMARY KEY,比如我们把学生信息表student_info的学号列声明为主键可以这么写:

    CREATE TABLE student_info (
        number INT PRIMARY KEY,
        name VARCHAR(5),
        sex ENUM('男', '女'),
        id_number CHAR(18),
        department VARCHAR(30),
        major VARCHAR(30),
        enrollment_time DATE
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  2. 我们也可以把主键的声明单独提取出来,用这样的形式声明:

    PRIMARY KEY (列名1, 列名2, ...)
    
    1

    然后把这个主键声明放到列定义的后边就好了。比如student_info的学号列声明为主键也可以这么写:

    CREATE TABLE student_info (
        number INT,
        name VARCHAR(5),
        sex ENUM('男', '女'),
        id_number CHAR(18),
        department VARCHAR(30),
        major VARCHAR(30),
        enrollment_time DATE,
        PRIMARY KEY (number)
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    值得注意的是,对于多个列的组合作为主键的情况,必须使用这种单独声明的形式,比如student_score表里的学号,科目的列组合作为主键,可以这么写:

    CREATE TABLE student_score (
        number INT,
        subject VARCHAR(30),
        score TINYINT,
        PRIMARY KEY (number, subject)
    );
    
    1
    2
    3
    4
    5
    6

    在我们创建表的时候就声明了主键的话,MySQL会对我们插入的记录做校验,如果新插入记录的主键值已经在表中存在了,那就会报错。

    另外,主键列默认是有NOT NULL属性,也就是必填的,如果填入NULL值会报错(先删除原来的student_info表,使用刚才所说的两种方式之一重新创建表之后仔执行下边的语句):

    mysql> INSERT INTO student_info(number) VALUES(NULL);
    ERROR 1048 (23000): Column 'number' cannot be null
    mysql>
    
    1
    2
    3

# UNIQUE 属性 🔥

对于不是主键的其他候选键,如果也想让MySQL在我们向表中插入新记录的时候帮助我们校验一下某个列或者列组合的值是否重复,那么我们可以把这个列或列组合添加一个UNIQUE属性,表明该列或者列组合的值是不允许重复的。与我们在建表语句中声明主键的方式类似,为某个列声明UNIQUE属性的方式也有两种:

  1. 如果我们想为单个列声明UNIQUE属性,可以直接在该列后填写UNIQUE或者UNIQUE KEY,比如在学生信息表student_info中,我们不允许两条学生基本信息记录中的身份证号是一样的,那我们可以为id_number列添加UNIQUE属性:

    CREATE TABLE student_info (
        number INT PRIMARY KEY,
        name VARCHAR(5),
        sex ENUM('男', '女'),
        id_number CHAR(18) UNIQUE,
        department VARCHAR(30),
        major VARCHAR(30),
        enrollment_time DATE
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  2. 我们也可以把UNIQUE属性的声明单独提取出来,用这样的形式声明:

    UNIQUE [约束名称] (列名1, 列名2, ...)
    
    1

    或者:

    UNIQUE KEY [约束名称] (列名1, 列名2, ...)
    
    1

    其实每当我们为某个列添加了一个UNIQUE属性,就像是在孙悟空头上带了个紧箍咒一样,从此我们插入的记录的该列的值就不能重复,所以为某个列添加一个UNIQUE属性也可以认为是为这个表添加了一个约束,我们就称之为UNIQUE约束。每个约束都可以有一个名字,像主键也算是一个约束,它的名字就是默认的PRIMARY。不过一个表中可以为不同的列添加多个UNIQUE属性,也就是添加多个UNIQUE约束,每添加一个UNIQUE约束,我们就可以给它起个名,这也是上边的约束名称的含义。不过约束名称是被中括号[]扩起来的,意味着我们写不写都可以,如果不写的话MySQL自己会帮我们起名。其实就像是自己生了个孩子,如果自己不起名的话,人家公安局的警察叔叔也得给孩子起个名上户口。

    为约束起名的事儿理解了之后,我们把这个UNIQUE属性的声明放到列定义的后边就好了。比如我们为student_info表的id_number(身份证号)列添加UNIQUE属性也可以这么写:

    CREATE TABLE student_info (
        number INT PRIMARY KEY,
        name VARCHAR(5),
        sex ENUM('男', '女'),
        id_number CHAR(18),
        department VARCHAR(30),
        major VARCHAR(30),
        enrollment_time DATE,
        UNIQUE KEY uk_id_number (id_number)
    );
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    可以看到,我们给这个UNIQUE约束起的名儿就是uk_id_number。

    不过值得注意的是,对于多个列的组合具有UNIQUE属性的情况,必须使用这种单独声明的形式。

    如果表中为某个列或者列组合定义了UNIQUE属性的话,MySQL会对我们插入的记录做校验,如果新插入记录在该列或者列组合的值已经在表中存在了,那就会报错!

# 主键和 UNIQUE 约束的区别

主键和UNIQUE约束都能保证某个列或者列组合的唯一性,但是:

  1. 一张表中只能定义一个主键,却可以定义多个UNIQUE约束!
  2. 规定:主键列不允许存放 NULL,而声明了UNIQUE属性的列可以存放NULL,而且NULL可以重复地出现在多条记录中!
  3. 这俩约束的列会自动添加索引!

提示

小贴士: 一个表的某个列声明了 UNIQUE 属性,那这个列的值不就不可以重复了么,为啥 NULL 这么特殊?哈哈,NULL 就是这么特殊。NULL 其实并不是一个值,它代表不确定,我们平常说某个列的值为 NULL,意味着这一列的值尚未被填入。

# NOT NULL 属性 🔥

有时候我们需要要求表中的某些列中必须有值,不能存放NULL,那么可以用这样的语法来定义这个列:

列名 列的类型 NOT NULL
1

比如我们把first_table表的first_column列定义一个NOT NULL属性。当然,我们在重新定义表之前需要把原来的表删掉:

mysql> DROP TABLE first_table;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE first_table (
    ->     first_column INT NOT NULL,
    ->     second_column VARCHAR(100) DEFAULT 'abc'
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>
1
2
3
4
5
6
7
8
9
10

这样的话,我们就不能再往这个字段里插入NULL值了,比如这样:

mysql> INSERT INTO first_table(first_column, second_column) VALUES(NULL, 'aaa');
ERROR 1048 (23000): Column 'first_column' cannot be null
mysql>
1
2
3

看到报了个错,提示first_column列不能存储NULL。

另外,一旦对某个列定义了NOT NULL属性,那这个列的默认值就不为NULL了。上边first_column并没有指定默认值,意味着我们在使用INSERT插入行时必须显式的指定这个列的值,而不能省略它,比如这样就会报错的:

mysql> INSERT INTO first_table(second_column) VALUES('aaa');
ERROR 1364 (HY000): Field 'first_column' doesn't have a default value
mysql>
1
2
3

可以看到执行结果提示我们first_column并没有设置默认值,所以在使用INSERT语句插入记录的时候不能省略掉这个列的值。

尽量避免存储 NULL,查询不便,索引效率不高

# 默认值 🔥

在书写INSERT语句插入记录的时候可以只指定部分的列,那些没有被显式指定的列的值将被设置为NULL,换一种说法就是列的默认值为NULL,NULL的含义是这个列的值还没有被设置。如果我们不想让默认值为NULL,而是设置成某个有意义的值,可以在定义列的时候给该列增加一个DEFAULT属性,就像这样:

列名 列的类型 DEFAULT 默认值
1

比如我们把first_table的second_column列的默认值指定为'abc',创建一下这个表:

mysql> CREATE TABLE first_table (
    ->     first_column INT,
    ->     second_column VARCHAR(100) DEFAULT 'abc'
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql>
1
2
3
4
5
6
7

然后插入一条数据后看看默认值是不是起了作用:

mysql> INSERT INTO first_table(first_column) VALUES(1);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM first_table;
+--------------+---------------+
| first_column | second_column |
+--------------+---------------+
|            1 | abc           |
+--------------+---------------+
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12

我们的插入语句并没有指定second_column的值,但是可以看到插入结果是按照我们规定的默认值'abc'来设置的。

如果我们不设置默认值,其实就相当于指定的默认值为NULL,比如first_table表并没有设置first_column列的默认值,那它的默认值就是NULL,也就是说上边的表定义语句和下边这个是等价的:

CREATE TABLE first_table (
    first_column INT DEFAULT NULL,
    second_column VARCHAR(100) DEFAULT 'abc'
);
1
2
3
4

这个从SHOW CREATE TABLE语句中也可以看出来:

mysql> SHOW CREATE TABLE first_table\G
*************************** 1. row ***************************
       Table: first_table
Create Table: CREATE TABLE `first_table` (
  `first_column` int(11) DEFAULT NULL,
  `second_column` varchar(100) DEFAULT 'abc'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10

# 外键

插入到学生成绩表student_score中的number(学号)列中的值必须能在学生基本信息表student_info中的number列中找到,否则如果一个学号只在成绩表里出现,而在基本信息表里找不到相应的记录的话,就相当于插入了不知道是哪个学生的成绩,这显然是荒谬的。为了防止这样荒谬的情况出现,MySQL给我们提供了外键约束机制。定义外键的语法是这样的:

CONSTRAINT [外键名称] FOREIGN KEY(列1, 列2, ...) REFERENCES 父表名(父列1, 父列2, ...);
1

其中的外键名称也是可选的,一个名字而已,我们不自己命名的话,MySQL 自己会帮助我们命名。

如果 A 表中的某个列或者某些列依赖与 B 表中的某个列或者某些列,那么就称 A 表为子表,B 表为父表。子表和父表可以使用外键来关联起来,上边例子中student_score表的number列依赖于student_info的number列,所以student_info就是一个父表,student_score就是子表。我们可以在student_score的建表语句中来定义一个外键:

CREATE TABLE student_score (
    number INT,
    subject VARCHAR(30),
    score TINYINT,
    PRIMARY KEY (number, subject),
    CONSTRAINT FOREIGN KEY(number) REFERENCES student_info(number)
);
1
2
3
4
5
6
7

这样,在对student_score表插入数据的时候,MySQL都会为我们检查一下插入的学号是否能在student_info表中找到,如果找不到则会报错。

提示

小贴士: 父表中被子表依赖的列或者列组合必须建立索引,如果该列或者列组合已经是主键或者有 UNIQUE 属性,那么它们也就被默认建立了索引。示例中 student_score 表依赖于 stuent_info 表的 number 列,而 number 列又是 stuent_info 的主键(注意上一章定义的 student_info 结构中没有把 number 列定义为主键,本章才将其定义为主键,如果你的机器上还没有将其定义为主键的话,赶紧修改表结构呗~),所以在 student_score 表中创建外键是没问题的。 当然至于什么是索引,不是我们从零蛋开始学习 MySQL 的同学们需要关心的事,等学完本书之后再去看《MySQL 是怎样运行的:从根儿上理解 MySQL》就懂了。

# AUTO_INCREMENT 属性

AUTO_INCREMENT翻译成中文可以理解为自动增长,简称自增。如果一个表中的某个列的数据类型是整数类型或者浮点数类型,那么这个列可以设置AUTO_INCREMENT属性。当我们把某个列设置了AUTO_INCREMENT属性之后,如果我们在插入新记录的时候不指定该列的值,或者将该列的值显式地指定为NULL或者0,那么新插入的记录在该列上的值就是当前该列的最大值加 1 后的值(有一点点绕,稍后一举例子大家就明白了)。我们可以用这样的语法来定义这个列:

列名 列的类型 AUTO_INCREMENT
1

比如我们想在first_table表里设置一个名为id的列,把这个列设置为主键,来唯一标记一条记录,然后让其拥有AUTO_INCREMENT属性,我们可以这么写:

mysql> DROP TABLE first_table;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE first_table (
    ->     id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    ->     first_column INT,
    ->     second_column VARCHAR(100) DEFAULT 'abc'
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11

先把原来的表删掉,然后在新表中增加了一个非负INT类型的id列,把它设置为主键而且具有AUTO_INCREMENT属性,那我们在插入新记录时可以忽略掉这个列,或者将列值显式地指定为NULL或0,但是它的值将会递增,看:

mysql> INSERT INTO first_table(first_column, second_column) VALUES(1, 'aaa');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO first_table(id, first_column, second_column) VALUES(NULL, 1, 'aaa');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO first_table(id, first_column, second_column) VALUES(0, 1, 'aaa');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM first_table;
+----+--------------+---------------+
| id | first_column | second_column |
+----+--------------+---------------+
|  1 |            1 | aaa           |
|  2 |            1 | aaa           |
|  3 |            1 | aaa           |
+----+--------------+---------------+
3 rows in set (0.01 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

可以看到,列id是从 1 开始递增的。在为列定义AUTO_INCREMENT属性的时候需要注意这几点:

  1. 一个表中最多有一个具有 AUTO_INCREMENT 属性的列。
  2. 具有 AUTO_INCREMENT 属性的列必须建立索引。主键和具有UNIQUE属性的列会自动建立索引。不过至于什么是索引,在学习 MySQL 进阶的时候才会介绍。
  3. 拥有 AUTO_INCREMENT 属性的列就不能再通过指定 DEFAULT 属性来指定默认值。
  4. 一般拥有 AUTO_INCREMENT 属性的列都是作为主键的属性,来自动生成唯一标识一条记录的主键值。

# 列的注释

在建表语句的末尾可以添加COMMENT语句来给表添加注释,其实我们也可以在每一个列末尾添加COMMENT语句来为列来添加注释,比方说:

CREATE TABLE first_table (
    id int UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键',
    first_column INT COMMENT '第一列',
    second_column VARCHAR(100) DEFAULT 'abc' COMMENT '第二列'
) COMMENT '第一个表';
1
2
3
4
5

# 影响展示外观的 ZEROFILL 属性

下边是正整数3的三种写法:

  • 写法一:3
  • 写法二:003
  • 写法三:000003

有的同学笑了,这不是脱了裤子放屁么,我在3前边加上一万个0最终的值也是0呀,这有啥用?提出这类问题的同学肯定没有艺术细胞,它们长的不一样啊 —— 有的数字前边没 0,有的数字前边 0 少,有的数字前边 0 多,可能有的人就觉得在数字前头补一堆 0 长得好看呢?

对于无符号整数类型的列,我们可以在查询数据的时候让数字左边补 0,如果想实现这个效果需要给该列加一个ZEROFILL属性(也可以理解为这是一个属于数据类型的属性),就像这样:

mysql> CREATE TABLE zerofill_table (
    ->     i1 INT UNSIGNED ZEROFILL,
    ->     i2 INT UNSIGNED
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql>
1
2
3
4
5
6
7

我们在zerofill_table表中创建了两个无符号整数列,不同的是i1列具有ZEROFILL属性,下边我们为这个表插入一条记录:

mysql> INSERT INTO zerofill_table(i1, i2) VALUES(1, 1);
Query OK, 1 row affected (0.00 sec)

mysql>
1
2
3
4

然后我们使用查询语句来展示一下刚插入的数据:

mysql> SELECT * FROM zerofill_table;
+------------+------+
| i1         | i2   |
+------------+------+
| 0000000001 |    1 |
+------------+------+
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9

对于具有ZEROFILL属性的i1列,在显示的时候在数字前边补了一堆 0,仔细数数发现是 9 个 0,而没有ZEROFILL属性的i2列,在显示的时候并没有在数字前补 0。为什么i1列会补 9 个 0 呢?我们查看一下zerofill_table的表结构:

mysql> SHOW CREATE TABLE zerofill_table\G
*************************** 1. row ***************************
       Table: zerofill_table
Create Table: CREATE TABLE `zerofill_table` (
  `i1` int(10) unsigned zerofill DEFAULT NULL,
  `i2` int(10) unsigned DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

mysql>
1
2
3
4
5
6
7
8
9
10

可以看到,其实i1和i2列的类型INT后边都加了一个(10),这个10就是所谓的显示宽度。显示宽度是在查询语句显示的结果中,如果声明了 ZEROFILL 属性的整数列的实际值的位数小于显示宽度时,会在实际值的左侧补 0,使补 0 的位数和实际值的位数相加正好等于显示宽度。我们也可以自己指定显示宽度,比方说这样:

mysql> DROP TABLE zerofill_table;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE zerofill_table (
    ->     i1 INT(5) UNSIGNED ZEROFILL,
    ->     i2 INT UNSIGNED
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO zerofill_table(i1, i2) VALUES(1, 1);
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM zerofill_table;
+-------+------+
| i1    | i2   |
+-------+------+
| 00001 |    1 |
+-------+------+
1 row in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

新创建的表中,i1字段的显示宽度是 5,所以最后的显示结果中补了 4 个 0。不过在使用ZEROFILL属性时应该注意下边几点:

  • 在展示查询结果时,某列数据自动补 0 的条件有这几个:

    • 该列必须是整数类型的
    • 该列必须有UNSIGNED ZEROFILL的属性
    • 该列的实际值的位数必须小于显示宽度
  • 在创建表的时候,如果声明了ZEROFILL属性的列没有声明UNSIGNED属性,那MySQL会为该列自动生成UNSIGNED属性。

    也就是说如果我们创建表语句是这样的:

    CREATE TABLE zerofill_table (
        i1 INT ZEROFILL,
        i2 INT UNSIGNED
    );
    
    1
    2
    3
    4

    MySQL会自动帮我们为i1列加上UNSIGNED属性,也就是这样:

    CREATE TABLE zerofill_table (
        i1 INT UNSIGNED ZEROFILL,
        i2 INT UNSIGNED
    );
    
    1
    2
    3
    4

    也就是说MySQL现在只支持对无符号整数进行自动补 0 的操作。

  • 每个整数类型都会有默认的显示宽度。

    比如TINYINT的默认显示宽度是4,INT的默认显示宽度是(11)... 如果加了UNSIGNED属性,则该类型的显示宽度减 1,比如TINYINT UNSIGNED的显示宽度是3,INT UNSIGNED的显示宽度是10。

  • 显示宽度并不会影响实际类型的实际存储空间。

    显示宽度仅仅是在展示查询结果时,如果整数的位数不够显示宽度的情况下起作用的,并不影响该数据类型要求的存储空间以及该类型能存储的数据范围,也就是说INT(1)和INT(10)仅仅在展示时可能有区别,在别的方面没有任何区别。比方说zerofill_table表中i1列的显示宽度是 5,而数字12345678的位数是 8,它照样可以被填入i1列中:

    mysql> INSERT INTO zerofill_table(i1, i2) VALUES(12345678, 12345678);
    Query OK, 1 row affected (0.01 sec)
    
    mysql>
    
    1
    2
    3
    4
  • 只有列的实际值的位数小于显示宽度时才会补 0,实际值的位数大于显示宽度时照原样输出。

    比方说我们刚刚把12345678存到了i1列里,在展示这个值时,并不会截短显示的数据,而是照原样输出:

    mysql> SELECT * FROM zero_table;
    +----------+----------+
    | i1       | i2       |
    +----------+----------+
    |    00001 |        1 |
    | 12345678 | 12345678 |
    +----------+----------+
    2 rows in set (0.00 sec)
    
    mysql>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • 对于没有声明ZEROFILL属性的列,显示宽度没有一毛钱卵用。

    只有在查询声明了ZEROFILL属性的列时,显示宽度才会起作用,否则忽略显示宽度这个东西的存在。

# 一个列同时具有多个属性

每个列可以同时具有多个属性,属性声明的顺序无所谓,各个属性之间用空白隔开就好了~

提示

注意,有的属性是冲突的,一个列不能具有两个冲突的属性,。如一个列不能既声明为 PRIMARY KEY,又声明为 UNIQUE KEY,不能既声明为 DEFAULT NULL,又声明为 NOT NULL。大家在使用过程中需要注意这一点。

# 查看表结构时的列属性

student_info表的结构:

mysql> DESC student_info;
+-----------------+-------------------+------+-----+---------+-------+
| Field           | Type              | Null | Key | Default | Extra |
+-----------------+-------------------+------+-----+---------+-------+
| number          | int(11)           | NO   | PRI | NULL    |       |
| name            | varchar(5)        | YES  |     | NULL    |       |
| sex             | enum('男','女')   | YES  |     | NULL    |       |
| id_number       | char(18)          | YES  | UNI | NULL    |       |
| department      | varchar(30)       | YES  |     | NULL    |       |
| major           | varchar(30)       | YES  |     | NULL    |       |
| enrollment_time | date              | YES  |     | NULL    |       |
+-----------------+-------------------+------+-----+---------+-------+
7 rows in set (0.00 sec)

mysql>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

可以看到:

  • NULL列代表该列是否可以存储NULL,值为NO时,表示不允许存储NULL,值为YES是表示可以存储NULL。
  • Key列存储关于所谓的键的信息,当值为PRI是PRIMARY KEY的缩写,代表主键;UNI是UNIQUE KEY的缩写,代表UNIQUE属性。
  • Default列代表该列的默认值。
  • Extra列展示一些额外的信息。比方说如果某个列具有AUTO_INCREMENT属性就会被展示在这个列里。

# 标识符的命名

像数据库名、表名、列名、约束名称或者我们之后会遇到的别的名称,这些名称统统被称为标识符。虽然MySQL中对标识符的命名没多少限制,但是却不欢迎下边的这几种命名:

  • 名称中全都是数字。
  • 名称中有空白字符
  • 名称使用了MySQL中的保留字

虽然某些名称可能会导致歧义,但是如果你坚持要使用的话,也不是不行,你可以使用反引号``来将你定义的名称扩起来,这样MySQL的服务器就能检测到你提供的是一个名称而不是别的什么东西

我们上边对表first_table的定义可以把里边的标识符全都使用反引号``引起来,这样语义更清晰一点:

CREATE TABLE `first_table` (
    `id` int UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    `first_column` INT,
    `second_column` VARCHAR(100) DEFAULT 'abc'
);
1
2
3
4
5

虽然反引号比较强大,但是我们还是建议大家不要起各种非主流的名称,也不要使用全数字、带有空白字符或者 MySQL 保留字的名称。由于 MySQL 是 C 语言实现的,所以在名称定义上还是尽量遵从 C 语言的规范吧,就是用小写字母、数字、下划线、美元符号等作为名称,如果有多个单词的话,各个单词之间用下划线连接起来,比如student、student_info啥的~

编辑
上次更新: 2021/01/17, 17:17:41
DDL—数据库
DML 🔥

← DDL—数据库 DML 🔥→

最近更新
01
线程生命周期
07-06
02
线程安全理论
06-24
03
并发简史
06-24
更多文章>
Theme by Vdoing | Copyright © 2019-2021 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×