三、mysql表的基本操作

上集回顾

上集我们介绍了在MySQL客户端书写命令的一些注意事项以及操作数据库的一些语句,并且创建了一个名为xiaohaizi的数据库。

表的操作

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

创建表

基本语法

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

给表起个名。
给表定义一些列,并且给这些列都起个名。
每一个列都需要定义一种数据类型,来规范它能存储的数据。
如果有需要的话,可以给这些列定义一些列的属性,比如不许为空,设置默认值等等,这些属性也叫做列的约束性条件,具体有哪些列的属性我们稍后会详细唠叨。
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把之前提到的学生基本信息表和成绩表给创建出来了,先把学生信息表搬下来看看:

学生基本信息表
三、mysql表的基本操作
很显然,这个表有学号、姓名、性别、身份证号、学院、专业、入学时间这几个列,其中的学号是整数类型的,入学时间是日期类型的,由于身份证号是固定的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
);
然后再看一下学生成绩表:
三、mysql表的基本操作

这个表有学号、科目、成绩这几个列,学号和成绩是整数类型的,科目是字符串类型的,所以我们创建一下这个表:

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列的值是1,second_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_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>
然后插入一条数据后看看默认值是不是起了作用:

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_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>
这样的话,我们就不能再往这个字段里插入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中,我们可以通过学号和科目这两个列的组合来确定唯一的一条成绩记录,所以学号、科目这两个列的组合可以作为学生成绩表的候选键。

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

如果主键只是单个列的话,可以直接在该列后声明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
);
我们也可以把主键的声明单独提取出来,用这样的形式声明:

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的,表明该列或者列组合的值是不允许重复的,这种列的属性叫做唯一性约束。同主键的定义一样,唯一性约束的定义也有两种方式:

如果具有唯一性约束的列是单个列的话,可以直接在该列后声明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
);
我们也可以把唯一性约束的声明单独提取出来,用这样的形式声明:

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会对我们插入的记录做校验,如果插入的值违反了唯一性约束的话就会报错!

主键和唯一性约束的区别

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

一张表中只能定义一个主键,却可以定义多个唯一性约束!
主键列不允许存放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>
先把原来的表删掉,然后在新表中增加了一个名为id、数据类型为INT UNSIGNED类型的列,并把它设置为主键而且具有递增属性,那我们插入数据的时候就可以不用管这个列,但是它的值将会递增,看:

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开始递增的。在使用递增属性的时候需要注意这几点:

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

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

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

创建表:

CREATE TABLE 表名 (
列名, 列的类型, [列的属性] COMMENT ‘列的注释’,
… (若干个列的信息)
) COMMENT ‘表的注释’;
删除表:DROP TABLE 表名;

各种约束性条件

方式一:

列名 列的类型 UNIQUE [KEY]
方式二:

UNIQUE [KEY] [约束名称] (列名1, 列名2, …)
方式一:

列名 列的类型 PRIMARY KEY
方式二:

PRIMARY KEY (列名1, 列名2, …)
默认值:在插入语句中没有指定该列的值的情况下,使用默认值,声明语法如下:

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

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

唯一性约束:唯一标识一条记录,一个表中可以有多个唯一性约束,并且值可以为NULL,声明语法:

外键:表A的某个列或列组合的值依赖表B的某个列或列组合的值,则成表A为子表,表B为父表,表A的该列或者列组合称为外键,声明外键的方式如下:

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

列名 列的类型 AUTO_INCREMENT