数据库和表的基本操作

栏目: 数据库 · 发布时间: 5年前

内容简介:我们知道当一条命令发送给了MySQL服务器之后,服务器处理完后就会给你发送回来响应的结果,然后显示到界面上。然后你就可以接着输入下一条命令了。

MySQL 使用表来存放数据,表的每一列都需要存放特定格式的数据,所以 MySQL 为不同的格式的数据定义了不同的类型,我们介绍了各种数值、字符串、时间和二进制类型的含义以及要求的存储空间。本集来看一下在 MySQL 中关于数据库和表的各种操作。

命令使用注意事项

我们知道 MySQL 的基本运行过程就是: 通过客户端程序发送命令给服务器程序,服务器程序按照接收的命令去操作实际的数据 。在我们使用黑框框启动了 MySQL 客户端程序之后,界面上会一直显示一行 mysql> 的提示符,你可以在它后边输入我们的命令然后按一下回车键,在书写命令的时候需要注意下边这几点:

  1. 命令结束符号。

    在书写完一个命令之后需要以下边这几个符号之一结尾:

    ;
    \g
    \G
    

    比如说我们执行一个简单的查询当前时间的命令:

    mysql> SELECT NOW();
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2018-02-06 17:50:55 |
    +---------------------+
    1 row in set (0.00 sec)
    
    mysql>
    复制代码

    其中的 SELECT 意味着这是一个查询命令, NOW()MySQL 内置的函数,用于返回当前时间。不过我们现在并不是深究具体的某个命令是什么意思,只是想介绍一下书写命令时需要注意的一些事情。结果中 1 row in set (0.00 sec) 的意思是结果只有1行数据,用时0.00秒。使用 \g 可以起到一样的效果:

    mysql> SELECT NOW()\g
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2018-02-06 17:50:55 |
    +---------------------+
    1 row in set (0.00 sec)
    
    mysql>
    复制代码

    \G 有一点特殊,它并不以表格的形式返回查询数据,而是以 垂直 的形式展现查询数据:

    mysql> SELECT NOW()\G
    *************************** 1. row ***************************
    NOW(): 2018-02-06 17:51:51
    1 row in set (0.00 sec)
    
    mysql>
    复制代码

    如果查询结果非常长的话,使用 \G 可以让我们看清结果。 如果显式格式没啥问题,那我们平时都使用分号 ; 作为命令结束符了~

  2. 命令可以随意换行。

    并不是按了回车键就提交命令了,只要按回车键的时候输入的语句里没有 ;\g 或者 \G 就算是语句没结束。比如上边查询当前时间的命令还可以这么写:

    mysql> SELECT
        -> NOW()
        -> ;
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2018-02-06 17:57:15 |
    +---------------------+
    1 row in set (0.00 sec)
    
    mysql>
    复制代码
  3. 可以一次提交多个命令

    我们可以在一条语句里写多个命令(命令之间用上面说的结束符分隔),比如这样:

    mysql> SELECT NOW(); SELECT NOW(); SELECT NOW();
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2018-02-06 18:00:05 |
    +---------------------+
    1 row in set (0.00 sec)
    
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2018-02-06 18:00:05 |
    +---------------------+
    1 row in set (0.00 sec)
    
    +---------------------+
    | NOW()               |
    +---------------------+
    | 2018-02-06 18:00:05 |
    +---------------------+
    1 row in set (0.00 sec)
    
    mysql>
    复制代码

    连着输入了3个查询当前时间的命令,只要没按回车键,就不会提交命令。

    小贴士: 后边我们还会介绍把命令都写在文件里,然后再批量执行文件中的命令,那个感觉更爽!

  4. 使用 \c 清除本次操作。

    如果你想放弃本次编写的命令,可以使用 \c 来清除,比如这样:

    mysql> SELECT NOW()\c
    mysql>
    复制代码

    如果不使用 \c ,那客户端会以为这是一个多行命令,还在一直傻傻的等你输入命令~

  5. 大小写问题。

    MySQL 默认对命令的大小写并没有限制,也就是说我们这样查询当前时间也是可以的:

    mysql> select now();
    +---------------------+
    | now()               |
    +---------------------+
    | 2018-02-06 18:23:01 |
    +---------------------+
    1 row in set (0.00 sec)
    
    mysql>
    复制代码

    不过按照习俗,这些命令、函数什么的都是要大写的,而一些名称类的东西,比如数据库名,表名、列名啥的都是要小写的,更多具体的书写规范等我们遇着再详细介绍。

  6. 字符串的表示。

    在命令里有时会使用到字符串,我们可以使用单引号 '' 或者双引号 "" 把字符串内容引起来,比如这样:

    mysql> SELECT 'aaa';
    +-----+
    | aaa |
    +-----+
    | aaa |
    +-----+
    1 row in set (0.00 sec)
    
    mysql>
    复制代码

    这个语句只是简单的把字符串 'aaa' 又输出来了而已。但是一定要在字符串内容上加上引号,不然的话 MySQL 服务器会把它当作列名,比如这样就会返回一个错误:

    mysql> SELECT aaa;
    ERROR 1054 (42S22): Unknown column 'aaa' in 'field list'
    mysql>
    复制代码

    但是 MySQL 中有一种叫 ANSI_QUOTES 的模式,如果开启了这种模式,双引号就有其他特殊的用途了,可能你并不能看懂我在说什么,但是这都不重要,重要的是建议你最好使用单引号来表示字符串~

当一条命令发送给了 MySQL 服务器之后,服务器处理完后就会给你发送回来响应的结果,然后显示到界面上。然后你就可以接着输入下一条命令了。

数据库相关操作

MySQL 中把某种类型的表的集合称为一个 数据库MySQL 服务器管理着若干个数据库,每个数据库下都可以有若干个表,画个图就是这样:

数据库和表的基本操作

展示数据库

在我们刚刚安装好 MySQL 的时候,它已经内建了许多数据库和表了,我们可以使用下边这个命令来看一下都有哪些数据库:

SHOW DATABASES;
复制代码

我自己的电脑上安装的 MySQL 版本是 5.7.21 ,看一下在这个版本里内建了哪些数据库(启动客户端软件,用你的用户名和密码登录后输入命令):

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.01 sec)

mysql>
复制代码

可以看到,这一版本的 MySQL 已经为我们内建了4个数据库,这些数据库都是给 MySQL 自己使用的,如果我们想使用 MySQL 存放自己的数据的话,首先需要创建一个属于自己的数据库。

创建数据库

创建数据库的语法贼简单:

CREATE DATABASE 数据库名;
复制代码

来实际操作一下:

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

mysql>
复制代码

我把我的名字 xiaohaizi 作为了数据库名称,敲完命令回车之后提示了一个 Query OK, 1 row affected (0.00 sec) 说明数据库创建成功了。然后我们再用 SHOW DATABASES 的命令查看一下现在有哪些数据库:

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| xiaohaizi          |
+--------------------+
5 rows in set (0.00 sec)

mysql>
复制代码

看到我们自己创建的数据库 xiaohaizi 就已经在列表里了。

IF NOT EXISTS

我们在一个数据库已经存在的情况下再使用 CREATE DATABASE 去创建这个数据库会产生错误:

mysql> CREATE DATABASE xiaohaizi;
ERROR 1007 (HY000): Can't create database 'xiaohaizi'; database exists
mysql>
复制代码

执行结果提示了一个 ERROR ,意思是数据库 xiaohaizi 已经存在!所以如果我们并不清楚数据库是否存在,可以使用下边的语句来创建数据库:

CREATE DATABASE IF NOT EXISTS 数据库名;
复制代码

这个命令的意思是如果指定的数据库不存在的话就创建它,否则什么都不做。我们试一试:

mysql> CREATE DATABASE IF NOT EXISTS xiaohaizi;
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql>
复制代码

可以看到语句执行成功了,报的 ERROR 错误也没有了,只是结果中有1个 warning 而已。这个 warning 只是 MySQL 善意的提醒我们数据库 xiaohaizi 不存在而已,并不会影响语句的执行。

小贴士: 前边说过MySQL的命令可以多条一起执行,可以在黑框框中一次输入多个命令,也可以把好多命令放到一个文件中执行。如果某一条命令的执行结果是产生了一个`ERROR`,MySQL会停止执行该命令之后的命令,但是如果仅仅是在执行结果中有`warning`的话,是不会中断执行的。

切换当前数据库

对于每一个连接到 MySQL 服务器的客户端,都有一个当前数据库的概念,我们创建的表默认都会被放到当前数据库中,切换当前数据库的命令也贼简单:

USE 数据库名称;
复制代码

所以在介绍创建表之前,我们应该把当前数据库切换到刚刚创建的数据库 xiaohaizi 上:

mysql> USE xiaohaizi;
Database changed
mysql>
复制代码

看到显示了 Database changed 说明当前数据库已经切换成功了。需要注意的是,在退出当前客户端之后,也就是你输入了 exit 或者 quit 命令之后或者直接把当前的黑框框页面关掉,当你再次调用 mysql -h 主机名 -u 用户名 -p 密码 的时候,相当于重新开启了一个客户端,需要重新调用 USE 数据库名称 的命令来选择一下当前数据库。

删除数据库

如果你创建的数据库没用了,我们还可以把它删掉,语法如下:

DROP DATABASE 数据库名;
复制代码

在真实的工作环境里,在删除数据库之前你需要先拿体温计量量是不是发高烧了,然后再找至少两个人核实一下自己是不是发烧了,然后你才敢执行删除数据库的命令。删除数据库意味着 里边的表就都被删除了,也就意味着你的数据都没了,所以是个极其危险的操作 ,使用时需要极其谨慎。不过我们这是学习环境,而且刚刚创建了 xiaohaizi 数据库,什么表都没往里头放,删了就删了吧:

mysql> DROP DATABASE xiaohaizi;
Query OK, 0 rows affected (0.01 sec)

mysql>
复制代码

然后看一下现在还有哪些数据库:

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.01 sec)

mysql>
复制代码

可以看到我们前边创建的 xiaohaizi 数据库就没有啦。

IF EXISTS

如果某个数据库并不存在,我们仍旧调用 DROP TABLE 语句去删除它,会报错的:

mysql> DROP DATABASE xiaohaizi;
ERROR 1008 (HY000): Can't drop database 'xiaohaizi'; database doesn't exist
mysql>
复制代码

如果想避免这种报错,可以使用这种形式的语句来删除数据库:

DROP DATABASE IF EXISTS 表名;
复制代码

再次删除一下 xiaohaizi

mysql> DROP DATABASE IF EXISTS xiaohaizi;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql>
复制代码

这回就不会报错啦!演示完删除数据库的流程之后还是把 xiaohaizi 数据库创建出来并且切换到当前数据库吧,毕竟我们之后还要在这个数据库里创建各种表呢~

表的操作

数据库建好之后,我们就可以接着创建真正存储数据的表了。创建表的时候首先需要描述清楚这个表长什么样,它有哪些列,这些列都是用来存什么类型的数据等等,这个对表的描述称为表的 模式 ( scheme )。有了表的模式之后,我们就可以着手把数据塞到这个表里了。表中的每一行也叫做一条 记录 ,每一列也叫做一个 字段

创建表

基本语法

创建一个表需要至少要完成下列事情:

约束性条件

MySQL 中创建表的基本语法就是这样的:

CREATE TABLE 表名 (
    列名1    列的类型    [列的属性],
    列名2    列的类型    [列的属性],
    ...
    列名n    列的类型    [列的属性]
);
复制代码

也就是说,我们在 CREATE TABLE 后写清楚我们定义的表的表名,然后在小括号 () 中定义上这个表的各个列的信息,包括列的列名、类型,如果有需要的话也可以定义这个列的属性,其中列的属性用中括号 [] 引起来的意思是可选的,也就是说可以有也可以没有,列名、列的类型、列的属性之间用空白字符分开就好,然后各个列的信息之间用逗号 , 分隔开。

小贴士: 我们也可以把这个创建表的语句都放在一行里(把换行删掉),分成多行并且加上缩进仅仅是为了美观而已~

废话不多说,赶紧创建一个超级简单的表瞅瞅:

CREATE TABLE first_table (
    first_column INT,
    second_column VARCHAR(100)
);
复制代码

我们新创建的这个表的名字叫做 first_table ,它有两个列,第一个列的列名是 first_column ,列的类型是 INT ,意味着只能存放整数型数据,第二个列的列名是 second_column ,列的类型是 VARCHAR(100) ,意味着这个列可以存放长度不超过100个字符的字符串。我们在客户端执行一下这个语句(当前数据库是 xiaohaizi ):

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

mysql>
复制代码

输出 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
);
复制代码

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

学生成绩表
学号 科目 成绩
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
);
复制代码

赶紧到你的客户端里填写创建这两个表的命令吧~

展示当前数据库中的表

我们刚才在 xiaohaizi 数据库里创建了几个表,那我们怎么查看 xiaohaizi 数据库下都有哪些表呢? MySQL 提供了这样的一个命令:

SHOW TABLES;
复制代码

该命令会展示出当前数据库中都有哪些表,我们执行一下:

mysql> show tables;
+---------------------+
| Tables_in_xiaohaizi |
+---------------------+
| first_table         |
| student_info        |
| student_score       |
+---------------------+
3 rows in set (0.01 sec)

mysql>
复制代码

我们刚才创建的表就都被展示出来了。

IF NOT EXISTS

和重复创建数据库一样,如果创建一个已经存在的表的话是会报错的,我们来试试重复创建一下 first_table 表:

mysql> CREATE TABLE first_table (
    ->     first_column INT,
    ->     second_column VARCHAR(100)
    -> );
ERROR 1050 (42S01): Table 'first_table' already exists
mysql>
复制代码

执行结果提示了一个 ERROR ,意思是 first_table 已经存在!所以如果想要避免这种尴尬,我们可以在创建表的时候使用这种形式:

CREATE TABLE IF NOT EXISTS 表名(
    各个列信息的定义 ...
);
复制代码

加入了 IF NOT EXISTS 的语句表示如果指定的表名不存在则创建这个表,如果不存在那就什么都不做。我们使用这种 IF NOT EXISTS 的语法再来创建一遍 first_table 表:

mysql> CREATE TABLE IF NOT EXISTS first_table (
    ->     first_column INT,
    ->     second_column VARCHAR(100)
    -> );
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql>
复制代码

可以看到语句执行成功了,报的 ERROR 错误也没有了,只是结果中有1个 warning 而已。

简单的表操作语句

在创建完表之后,我们只是创建了一个壳子,里边什么数据都没有。使用表的目的当然是存储数据啦,下边我们来看几个简单的查询与插入语句,更多关于表中数据的操作语句我们之后会详细唠叨的。

简单的查询语句

如果我们想查看某个表里已经存储了哪些数据,可以用下边这个语句:

SELECT * FROM 表名;
复制代码

比如我们想看看前边创建的 first_table 表中有哪些数据,可以这么写:

mysql> SELECT * FROM first_table;
Empty set (0.01 sec)

mysql>
复制代码

很遗憾,我们从来没有向表中插入过数据,所以查询结果显示的是 Empty set ,表示什么都没查出来~

简单插入语句

MySQL 插入数据的时候是 以行为单位 的,语法格式如下:

INSERT INTO 表名(列1, 列2, ...) VALUES(列1的值,列2的值, ...);
复制代码

也就是说我们可以在表名后边的括号中指定要插入数据的列,然后在 VALUES 后边的括号中按指定的列顺序填入对应的值,我们来为 first_table 表插入第一行数据:

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

mysql>
复制代码

这个语句的意思就是我们要向 first_table 表中插入一行数据, first_column 列的值是 1second_column 列的值是 'aaa' 。看一下现在表中的数据:

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

mysql>
复制代码

第一行数据就插入成功了!

我们 也可以只指定部分的列 ,没有显式指定的列的值将被设置为 NULL ,意思是还没有指定值,比如这样写:

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

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

mysql>
复制代码

第一条插入语句我们只指定了 first_column 列的值是2,而没有指定 second_column 的值,所以 second_column 的值就是 NULL ;第二条插入语句我们只指定了 second_column 的值是 'ccc' ,而没有指定 first_column 的值,所以 first_column 的值就是 NULL ,也表示没有数据~ 看一下现在表中的数据:

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

mysql>
复制代码

批量插入

每插入一行数据写一条语句也不是不行,但是对人来说太烦了,而且每插入一行数据提交一个请求给服务器远没有一次把所有插入的数据提交给服务器效率高,所以 MySQL 为我们提供了批量插入的语句:

INSERT INTO 表名(列1,列2, ...) VAULES(列1的值,列2的值, ...), (列1的值,列2的值, ...), (列1的值,列2的值, ...), ...;
复制代码

也就是在原来的单条插入语句后边多写几项插入行的内容,用逗号分隔开就好了,举个例子:

mysql> INSERT INTO first_table(first_column, second_column) VALUES(4, 'ddd'), (5, 'eee'), (6, 'fff');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM first_table;
+--------------+---------------+
| first_column | second_column |
+--------------+---------------+
|            1 | aaa           |
|            2 | NULL          |
|         NULL | ccc           |
|            4 | ddd           |
|            5 | eee           |
|            6 | fff           |
+--------------+---------------+
6 rows in set (0.01 sec)

mysql>
复制代码

可以看到3行记录就插入成功了!

删除表

如果一个表不用了,就可以删掉了,在真实环境中删除表一定要慎重谨慎,失去了的就再也回不来了~ 看一下删除的语法:

DROP TABLE 表1, 表2, ..., 表n;
复制代码

也就是说我们可以同时删除多个表。我们现在把 first_table 表给删掉看看:

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

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

mysql>
复制代码

可以看到现在数据库 xiaohaizi 中没有了 first_table 表,说明删除成功了!

IF EXISTS

如果我们尝试删除某个不存在的表的话会报错:

mysql> DROP TABLE first_table;
ERROR 1051 (42S02): Unknown table 'xiaohaizi.first_table'
mysql>
复制代码

提示我们要删除的表并不存在,如果想避免报错,可以使用这种删除语法:

DROP TABLE IF EXISTS 表名;
复制代码

然后再删除一下不存在的 first_table 表:

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

mysql>
复制代码

这样就不报错了~

约束性条件(列的属性)

对于某些列来说,可能有一些特殊含义或者用法,我们把这些特殊的含义或用法称为列的 属性 ,也可以称为列的 约束性条件 ,在创建表的时候可以显式的定义出来。下边我们看都有哪些约束性条件以及怎么在创建表的时候把它们定义出来。

默认值

前边介绍 INSERT 语句的时候说过,如果在指定的插入列中省略了某些列,那这些列的值将被设置为 NULL ,也就是列的默认值为 NULL ,表示没有设置值。我们在创建表的时候也可以指定一些有意义的默认值,指定方式如下:

列名 列的类型 DEFAULT 默认值
复制代码

比如我们把 first_tablesecond_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>
复制代码

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

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>
复制代码

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

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

CREATE TABLE first_table (
    first_column INT DEFAULT NULL,
    second_column VARCHAR(100) DEFAULT 'abc'
);
复制代码

非空约束

对于某些列,我们要求它们是必填的,也就是不允许存放 NULL 值,我们用这样的语法来定义这个列:

列名 列的类型 NOT NULL
复制代码

比如我们把 first_tablefirst_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>
复制代码

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

mysql> INSERT INTO first_table(first_column, second_column) VALUES(NULL, 'aaa');
ERROR 1048 (23000): Column 'first_column' cannot be null
mysql>
复制代码

可以看到,弹出了错误提示。

一旦对某个列定义了 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>
复制代码

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

主键

有时候在我们的表里可以通过某个列或者某些列确定唯一的一条记录,我们就可以把这个列或者这些列称为 候选键 。比如在学生信息表 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
    );
    复制代码
  2. 我们也可以把主键的声明单独提取出来,用这样的形式声明:

    PRIMARY KEY (列名1, 列名2, ...)
    复制代码

    然后把这个主键声明放到列定义的后边就好了。比如 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)
    );
    复制代码

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

    CREATE TABLE student_score (
        number INT,
        subject VARCHAR(30),
        score TINYINT,
        PRIMARY KEY (number, subject)
    );
    复制代码

在我们创建表的时候就声明了主键的话, MySQL 会对我们插入的记录做校验,如果两条记录里有相同的主键值的话就会报错

另外,主键列默认是 NOT NULL 的,也就是必填的,如果填入 NULL 值会报错(先删除原来的 student_info 表,使用上边的两种方式之一重新创建表):

mysql> INSERT INTO student_info(number) VALUES(NULL);
ERROR 1048 (23000): Column 'number' cannot be null
mysql>
复制代码

所以大家在插入数据的时候至少别忘了给主键列赋值哈~

唯一性约束

对于不是主键的其他候选键,如果我们也想让 MySQL 替我们校验数据的唯一性,那我们可以把这个列或列组合声明为 UNIQUE 的,表明该列或者列组合的值是不允许重复的,这种列的属性叫做 唯一性约束 。同主键的定义一样, 唯一性约束 的定义也有两种方式:

  1. 如果具有 唯一性约束 的列是单个列的话,可以直接在该列后声明 UNIQUE 或者 UNIQUE KEY ,比如在学生信息表 student_info 中,我们不允许两条学生记录中的身份证号是一样的,那我们让 id_number 这一列具有唯一性约束。

    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
    );
    复制代码
  2. 我们也可以把唯一性约束的声明单独提取出来,用这样的形式声明:

    UNIQUE [约束名称] (列名1, 列名2, ...)
    复制代码

    或者:

    UNIQUE KEY [约束名称] (列名1, 列名2, ...)
    复制代码

    其中的 约束名称 是可选的,其实就是我们为这个唯一性约束起的一个名字而已,如果不起名字的话该名称默认和列名相同,这个不重要哈~ 然后把这个唯一性约束声明放到列定义的后边就好了。比如 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,
        UNIQUE KEY (id_number)
    );
    复制代码

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

如果表中定义了唯一性约束的话, MySQL 会对我们插入的记录做校验,如果插入的值违反了唯一性约束的话就会报错

主键和唯一性约束的区别

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

  1. 一张表中只能定义一个主键,却可以定义多个唯一性约束
  2. 主键列不允许存放NULL值,而普通的唯一性约束列可以存放NULL值

小贴士: 你可能会问为啥主键列不允许存放NULL值,而普通的唯一性约束列却可以呢?哈哈,这涉及到底层存储的事情,现在你只需要记住这个规定就好了,如果你想知道更多的事情,那就继续往后看呗~

外键

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

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

其中的 外键名称 也是可选的,一个名字而已有没有都行,不是很重要~ 如果A表中的某个列或者某些列依赖与B表中的某个列或者某些列,那么就称A表为 子表 ,B表为 父表 。子表和父表可以使用外键来关联起来,上边例子中 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)
);
复制代码

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

小贴士: 父表中作为外键的列或者列组合必须建立索引,主键和具有唯一性约束的列默认的都建立了索引,置于什么是索引,我们之后会详细唠叨的。

自增

如果一个表中的某个列是数值类型的,包括整数类型和浮点数类型,那么这个列可以设置 自增 属性。所谓自增,意思是如果我们在插入数据的时候不指定该列的值,那么该列的值就是上一列的值加1后的值,定义语法就是这样:

列名 列的类型 AUTO_INCREMENT
复制代码

比如我们想在 first_table 里设置一个自增列 id ,并把这个列设置为主键,来唯一标记一行记录,我们可以这么写:

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>
复制代码

先把原来的表删掉,然后在新表中增加了一个非负 int 类型的 id 列,并把它设置为主键而且具有递增属性,那我们插入数据的时候就可以不用管这个列,但是它的值将会递增,看:

mysql> INSERT INTO first_table(first_column, second_column) VALUES(1, 'aaa'), (2, 'bbb'), (3, 'ccc');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

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

mysql>
复制代码

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

  1. 一个表中最多有一个递增列
  2. 一般只为整数类型的列定义递增属性,浮点数类型基本不用递增属性
  3. 具有 AUTO_INCREMENT 属性的列必须建立索引 。主键和具有唯一性约束的列会自动建立索引,至于什么是索引,我们后边会详细唠叨。
  4. 一般递增列都是作为主键的属性,来自动生成唯一标识一个记录的主键值
  5. 因为具有 AUTO_INCREMENT 属性的列是从1开始递增的,所以最好用 UNSIGNED 来修饰这个列,可以提升正数的表示范围

约束性条件的组合

每个列可以有多个约束性条件,声明的顺序无所谓,各个约束性条件之间用空白隔开就好了~

小贴士: 注意,有的约束性条件是冲突的,一个列不能具有两个冲突的约束性条件,比如一个列不能既声明为`PRIMARY KEY,又声明为UNIQUE KEY`,不能既声明为`DEFAULT NULL`,又声明为`NOT NULL`。大家在使用过程中需要注意这一点。

添加注释

我们可以对每个列信息以及表作注释,具体语法如下:

CREATE TABLE 表名 (
    列1 列的类型 [列的属性] COMMENT '列1的注释信息',
    列2 列的类型 [列的属性] COMMENT '列2的注释信息',
    列3 列的类型 [列的属性] COMMENT '列3的注释信息',
) COMMENT '表的注释信息';
复制代码

比如我们可以这样创建我们的 first_table 表:

CREATE TABLE first_table (
    id int UNSIGNED AUTO_INCREMENT PRIMARY KEY COMMENT '自增主键',
    first_column INT COMMENT '第一列',
    second_column VARCHAR(100) DEFAULT 'abc' COMMENT '第二列'
) COMMENT '第一个表';
复制代码

注释没必要太长,言简意赅即可,毕竟是给人看的,让人看明白是个啥意思就OK了。为了我们自己的方便,也为了阅读你创建的人的方便,请遵守一下职业道德,写个注释吧~ 求求你了~ 求求你了~ 求求你了~

标识符的命名

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

  1. 名称中全都是数字。

    因为在一些 MySQL 命令中也会使用到数字,如果你起的名称中全部都是数字,会让 MySQL 服务器分别不清哪个是名称,哪个是数字了。比如名称 1234567 就是非法的。

  2. 名称中有空白字符

    MySQL 命令是靠空白字符来分隔各个单词的,比如下边这两行命令是等价的:

    CREATE DATABASE xiaohaizi;
    CREATE   DATABASE   xiaohaizi;
    复制代码

    但是如果你定义的名称中有空白字符,这样会被当作两个词去处理,就会造成歧义。比如名称 word1 word2 word3 就是非法的。

  3. 名称使用了 MySQL 中的保留字

    MySQL 中有很多保留的词是会被当作命令处理的,比如 CREATEDATABASEDROPTABLE 等等等等,我们稍后还会介绍大量的命令,这些命令用到的单词都是作为MySQL的保留字,如果你的名称用到了这些词儿也会导致歧义。比如名称 create 就是非法的。

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

1234567`
`word1 word2    word3`
`create`
复制代码

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

CREATE TABLE `first_table` (
    `id` int UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    `first_column` INT,
    `second_column` VARCHAR(100) DEFAULT 'abc'
);
复制代码

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

查看表结构

有时候我们可能忘记了自己定义的表的结构,可以使用下边这些语句来查看,它们起到的效果都是一样的:

DESCRIBE 表名;
DESC 表名;
EXPLAIN 表名;
SHOW COLUMNS FROM 表名;
SHOW FIELDS FROM 表名;
复制代码

比如我们看一下 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>
复制代码

可以看到,这个 student_info 表的各个列的类型和属性就都展示出来了,其中 PRIPRIMARY KEY 的缩写, UNIUNIQUE KEY 的缩写。

小贴士: 请注意`number`列的类型是`int(11)`,这个小括号里的`11`是什么意思?这个`11`其实是所谓的显示宽度,我们稍后马上唠叨。

如果你看不惯这种详细展示各个字段的的信息,我们还可以使用下边这个语句来查看表结构:

SHOW CREATE TABLE 表名;
复制代码

比如:

mysql> SHOW CREATE TABLE student_info;
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table        | Create Table                                                                                                                                                                                                                                                                                                                                                                                        |
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| student_info | CREATE TABLE `student_info` (
  `number` int(11) NOT 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,
  PRIMARY KEY (`number`),
  UNIQUE KEY `id_number` (`id_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8   |
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>
复制代码

由于这行数据太长了,所以输出效果并不是很好,所以把原来用于标记语句结束的分号 ; 改为 \G ,这样的效果可能好点:

mysql> SHOW CREATE TABLE student_info\G
*************************** 1. row ***************************
       Table: student_info
Create Table: CREATE TABLE `student_info` (
  `number` int(11) NOT 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,
  PRIMARY KEY (`number`),
  UNIQUE KEY `id_number` (`id_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql>
复制代码

可以看到,使用 SHOW CREATE TABLE 这种语句展示出来的表结构就是我们平时创建表的语句。而且 MySQL 默认为主键字段加了 NOT NULL 属性,为其他字段加了 DEFAULT NULL 属性,而且还给 身份证号 的唯一性约束起了和列名一样的名称。

小贴士: 你可能疑惑的是在表定义末尾的`ENGINE=InnoDB DEFAULT CHARSET=utf8`是什么意思,这个是指定表的存储引擎和默认字符集,这些内容后边会有专门的专题来详细唠叨的,你现在不用关心~

ZEROFILL与显示宽度

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

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

mysql>
复制代码

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

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

mysql>
复制代码

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

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

mysql>
复制代码

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

mysql> DESC zero_table;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type                      | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| i1    | int(10) unsigned zerofill | YES  |     | NULL    |       |
| i2    | int(10) unsigned          | YES  |     | NULL    |       |
+-------+---------------------------+------+-----+---------+-------+
2 rows in set (0.01 sec)

mysql>
复制代码

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

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

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

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

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

mysql>
复制代码

新创建的表中, i1 字段的显示宽度是5,所以最后的显示结果中补了4个0。

注意事项

  1. 在查询时,数据自动补0的条件有这几个

    UNSIGNED ZEROFILL
    
  2. 在创建表的时候,如果声明了 ZEROFILL 属性的列没有声明 UNSIGNED 属性,那 MySQL 会为该列自动生成 UNSIGNED 属性

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

    CREATE TABLE zero_table (
        i1 INT ZEROFILL,
        i2 INT UNSIGNED
    );
    复制代码

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

    CREATE TABLE zero_table (
        i1 INT UNSIGNED ZEROFILL,
        i2 INT UNSIGNED
    );
    复制代码
  3. 每个整数类型都会有默认的显示宽度

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

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

    也就是说 INT(1)INT(10) 其实并没有什么区别,比方说 zero_table 表中 i1 列的显示宽度是5,而数字 12345678 的位数是8,它照样可以被填入 i1 列中:

    mysql> INSERT INTO zero_table(i1, i2) VALUES(12345678, 12345678);
    Query OK, 1 row affected (0.01 sec)
    复制代码
  5. 对于没有声明 ZEROFILL 属性的列,显示宽度没有一毛钱卵用

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

  6. 只有列的实际值的位数小于显示宽度时才会补0,实际值的位数大于显示宽度时照原样输出

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

    mysql> SELECT * FROM zero_table;
    +----------+----------+
    | i1       | i2       |
    +----------+----------+
    |    00001 |        1 |
    | 12345678 | 12345678 |
    +----------+----------+
    2 rows in set (0.00 sec)
    
    mysql>
    复制代码

没有选择默认数据库时对表的操作

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

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

mysql>
复制代码

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

数据库名.表名
复制代码

比如我们需要查询 first_table 表中的数据,可以这么写:

SELECT * FROM xiaohaizi.first_table;
复制代码

查看表结构:

SHOW CREATE TABLE xiaohaizi.first_table\G
复制代码

在其他不确定当前数据库的情况下,使用到表的地方也都需要加上所属的数据库名,就不一一列举了。

修改表

在表创建好之后如果对表的结构不满意,比如想增加或者删除一列,想修改某一列的数据类型或者约束性条件,想对表名或者列名进行重命名,这些操作统统都算是修改表结构。 MySQL 给我们提供了一系列修改表结构的语句。

修改表名

我们可以通过下边这两种方式来修改表的名称:

  1. 方式一:

    ALTER TABLE 旧表名 RENAME TO 新表名;
    复制代码

    我们把 first_table 表的名称修改为 first_table1

    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>
    复制代码

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

  2. 方式二:

    RENAME TABLE 旧表名1 TO 新表名1, 旧表名2 TO 新表名2, ... 旧表名n TO 新表名n;
    复制代码

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

如果在修改表名的时候指定了数据库名,还可以转移表所属的数据库,我们先再创建一个数据库 dahaizi

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

mysql>
复制代码

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

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

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

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

mysql>
复制代码

可以看到 first_table1 就从数据库 xiaohaizi 转移到 dahaizi 里边了。我们再换一种方式把它转回来,并且更名为 first_table

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

mysql>
复制代码

增加列

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

ALTER TABLE 表名 ADD COLUMN 列名 列的类型 [列的属性];
复制代码

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

mysql> ALTER TABLE first_table ADD COLUMN third_column CHAR(4) DEFAULT '1234' COMMENT '第三列';
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC first_table;
+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| id            | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| first_column  | int(11)          | YES  |     | NULL    |                |
| second_column | varchar(100)     | YES  |     | abc     |                |
| third_column  | char(4)          | YES  |     | 1234    |                |
+---------------+------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)

mysql>
复制代码

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

增加列到特定位置

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

  1. 添加到第一列:

    ALTER TABLE 表名 ADD COLUMN 列名 列的类型 [列的属性] FIRST;
    复制代码

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

    mysql> ALTER TABLE first_table ADD COLUMN fourth_column CHAR(4) DEFAULT '1234' COMMENT '第四列' FIRST;
    Query OK, 0 rows affected (0.05 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> DESC first_table;
    +---------------+------------------+------+-----+---------+----------------+
    复制代码

| Field | Type | Null | Key | Default | Extra | +---------------+------------------+------+-----+---------+----------------+ | fourth_column | char(4) | YES | | 1234 | | | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | first_column | int(11) | YES | | NULL | | | second_column | varchar(100) | YES | | abc | | | third_column | char(4) | YES | | 1234 | | +---------------+------------------+------+-----+---------+----------------+ 5 rows in set (0.00 sec)

mysql>
```
看到插入成功了。
复制代码
  1. 添加到指定列的后边:

    ALTER TABLE 表名 ADD COLUMN 列名 列的类型 [列的属性] AFTER 指定列名;
    复制代码

    再插入一个 fifth_columnfirst_column 后边瞅瞅:

    mysql> ALTER TABLE first_table ADD COLUMN fifth_column CHAR(4) DEFAULT '1234' COMMENT '第五列' AFTER first_column;
    Query OK, 0 rows affected (0.05 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> DESC first_table;
    +---------------+------------------+------+-----+---------+----------------+
    复制代码

| Field | Type | Null | Key | Default | Extra | +---------------+------------------+------+-----+---------+----------------+ | fourth_column | char(4) | YES | | 1234 | | | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | first_column | int(11) | YES | | NULL | | | fifth_column | char(4) | YES | | 1234 | | | second_column | varchar(100) | YES | | abc | | | third_column | char(4) | YES | | 1234 | | +---------------+------------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec)

mysql>
```
`fifth_column`列就被插到`first_column`列后边了。
复制代码

删除列

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

ALTER TABLE DROP COLUMN 列名;
复制代码

我们把刚才向 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> DESC first_table;
+---------------+------------------+------+-----+---------+----------------+
| Field         | Type             | Null | Key | Default | Extra          |
+---------------+------------------+------+-----+---------+----------------+
| id            | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| first_column  | int(11)          | YES  |     | NULL    |                |
| second_column | varchar(100)     | YES  |     | abc     |                |
+---------------+------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

mysql>
复制代码

可以看到删除成功了。

修改列信息

修改列的信息有下边这两种方式:

  1. 方式一:

    ALTER TABLE 表名 MODIFY 列名 新数据类型 [新属性];
    复制代码

    我们来修改一下 first_table 表的 second_column 列,把它修改为 VARCHAR(2) 以及具有 NOT NULL 约束条件:

    mysql> ALTER TABLE first_table MODIFY second_column VARCHAR(2) NOT NULL COMMENT '第二列';
    ERROR 1406 (22001): Data too long for column 'second_column' at row 1
    mysql>
    复制代码

    咦,看到报了个错,意思是 second_column 列里存放的数据太大了,我们看看都存了哪些数据:

    mysql> SELECT * FROM first_table;
    +----+--------------+---------------+
    | id | first_column | second_column |
    +----+--------------+---------------+
    |  1 |            1 | aaa           |
    |  2 |            2 | bbb           |
    |  3 |            3 | ccc           |
    +----+--------------+---------------+
    3 rows in set (0.00 sec)
    
    mysql>
    复制代码

    原来存放的数据是 'aaa''bbb''ccc' ,它们都是包含3个字符的字符串。现在我们要把 second_column 列的数据类型改为 VARCHAR(2) ,而 VARCHAR(2) 最多只能存放两个字符,所以才会报错了!知道了错误原因后,我们把类型改为 VARCHAR(3) 试试:

    mysql> ALTER TABLE first_table MODIFY second_column VARCHAR(3) NOT NULL COMMENT '第二列';
    Query OK, 3 rows affected (0.03 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    mysql> DESC first_table;
    +---------------+------------------+------+-----+---------+----------------+
    复制代码

| Field | Type | Null | Key | Default | Extra | +---------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | first_column | int(11) | YES | | NULL | | | second_column | varchar(3) | NO | | NULL | | +---------------+------------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)

mysql>
```
好了,这回就对了。这个过程也提醒我们:<span style="color:red">不能随便修改列信息,修改后的数据类型和属性一定要兼容表中现有的数据!</span>。
复制代码
  1. 方式二:

    ALTER TABLE 表名 CHANGE 旧列名 新列名 新数据类型 [新属性];
    复制代码

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

    mysql> ALTER TABLE first_table CHANGE second_column second_column1 VARCHAR(3) NOT NULL COMMENT '第二列';
    Query OK, 0 rows affected (0.01 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> DESC first_table;
    +----------------+------------------+------+-----+---------+----------------+
    复制代码

| Field | Type | Null | Key | Default | Extra | +----------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | first_column | int(11) | YES | | NULL | | | second_column1 | varchar(3) | NO | | NULL | | +----------------+------------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)

mysql>
```
我们只是把`second_column`的列名修改了一下而已,并没有改动它的数据类型和属性,所以直接把旧的数据类型和属性抄过来就好了,可以看到结果名称已经被修改了。
复制代码

修改列排列位置

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

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

    ALTER TABLE 表名 MODIFY 列名 列的类型 列的属性 FIRST;
    复制代码

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

    mysql> DESC first_table;
    +----------------+------------------+------+-----+---------+----------------+
    复制代码

| Field | Type | Null | Key | Default | Extra | +----------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | first_column | int(11) | YES | | NULL | | | second_column1 | varchar(3) | NO | | NULL | | +----------------+------------------+------+-----+---------+----------------+ 3 rows in set (0.01 sec)

mysql>
```
可以看到,列的顺序依次是: `id`、`first_column`、`second_column1`。现在我们想把`first_column`放在第一列可以这么写:
```
mysql>  ALTER TABLE first_table MODIFY first_column int(11)  COMMENT '第一列' FIRST;
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> DESC first_table;
+----------------+------------------+------+-----+---------+----------------+
复制代码

| Field | Type | Null | Key | Default | Extra | +----------------+------------------+------+-----+---------+----------------+ | first_column | int(11) | YES | | NULL | | | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | second_column1 | varchar(3) | NO | | NULL | | +----------------+------------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)

mysql>
```
看到`first_column`已经成为第一列了!
复制代码
  1. 将列放到指定列的后边:

    ALTER TABLE 表名 MODIFY 列名 列的类型 列的属性 after 指定列名;
    复制代码

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

    mysql> ALTER TABLE first_table MODIFY first_column int(11)  COMMENT '第一列' AFTER second_column1;
    Query OK, 0 rows affected (0.04 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> DESC first_table;
    +----------------+------------------+------+-----+---------+----------------+
    复制代码

| Field | Type | Null | Key | Default | Extra | +----------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | second_column1 | varchar(3) | NO | | NULL | | | first_column | int(11) | YES | | NULL | | +----------------+------------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)

mysql>
```
复制代码

一条语句中包含多个修改操作

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

ALTER TABLE 表名 操作1, 操作2, ..., 操作n;
复制代码

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

ALTER TABLE first_table DROP COLUMN third_column, DROP COLUMN fourth_column, DROP COLUMN fifth_column;
复制代码

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

总结

  1. MySQL服务器 可以包含若干数据库,每个数据库中可以包含若干个表。

  2. 数据库相关操作如下:

    SHOW DATABASES;
    CREATE DATABASE 数据库名;
    USE 数据库名
    DROP DATABASE 数据库名
    
  3. 表结构的相关操作如下:

    • 创建表:

      CREATE TABLE 表名 (
          列名, 列的类型, [列的属性] COMMENT '列的注释',
          ... (若干个列的信息)
      ) COMMENT '表的注释';
      复制代码
    • 删除表: DROP TABLE 表名;

    • 修改表:

      • 修改表名:

        • 方式一:

          ALTER TABLE 旧表名 RENAME TO 新表名;
          复制代码
        • 方式二:

          RENAME TABLE 旧表名1 TO 新表名1, 旧表名2 TO 新表名2, ... 旧表名n TO 新表名n;
          复制代码
      • 添加列:

        ALTER TABLE 表名 ADD COLUMN 列名 列的类型 [列的属性] [FIRST|AFTER 指定列名];
        复制代码
      • 删除列:

        ALTER TABLE DROP COLUMN 列名;
        复制代码
      • 修改列信息:

        • 方式一:

          ALTER TABLE 表名 MODIFY 列名 新数据类型 [新属性] [FIRST|AFTER 指定列名];
          复制代码
        • 方式二:

          ALTER TABLE 表名 CHANGE 旧列名 新列名 新数据类型 [新属性] [FIRST|AFTER 指定列名];
          复制代码
  4. 各种约束性条件

    • 默认值:在插入语句中没有指定该列的值的情况下,使用默认值,声明语法如下:

      列名 列的类型 DEFAULT 默认值
      复制代码
    • 非空约束:声明了该属性的列不允许插入 NULL 值,声明语法:

      列名 列的类型 NOT NULL
      复制代码
    • 主键:唯一标识一条记录,并且一个表中最多字能有一个主键,主键值不能为 NULL ,声明语法:

      • 方式一:

        列名 列的类型 PRIMARY KEY
        复制代码
      • 方式二:

        PRIMARY KEY (列名1, 列名2, ...)
        复制代码
    • 唯一性约束:唯一标识一条记录,一个表中可以有多个唯一性约束,并且值可以为 NULL ,声明语法:

      • 方式一:

        列名 列的类型 UNIQUE [KEY]
        复制代码
      • 方式二:

        UNIQUE [KEY] [约束名称] (列名1, 列名2, ...)
        复制代码
    • 外键:表A的某个列或列组合的值依赖表B的某个列或列组合的值,则成表A为子表,表B为父表,表A的该列或者列组合称为外键,声明外键的方式如下:

      CONSTRAINT [外键名称] FOREIGN KEY(列1, 列2, ...) REFERENCES 父表名(父列1, 父列2, ...);
      复制代码
    • 自增:在插入语句没有包含自增列的情况下,该列的值会递增,声明方式如下:

      列名 列的类型 AUTO_INCREMENT
      复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

代码整洁之道

代码整洁之道

马丁 / 人民邮电出版社 / 2011-1 / 59.00元

《代码整洁之道(英文版)》提出一种观念:代码质量与其整洁度成正比。干净的代码,既在质量上较为可靠,也为后期维护、升级奠定了良好基础。作为编程领域的佼佼者,《代码整洁之道(英文版)》作者给出了一系列行之有效的整洁代码操作实践。这些实践在《代码整洁之道(英文版)》中体现为一条条规则(或称“启示”),并辅以来自现实项目的正、反两面的范例。只要遵循这些规则,就能编写出干净的代码,从而有效提升代码质量。 ......一起来看看 《代码整洁之道》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具