第6章、列的属性
标签: MySQL是怎样使用的新版
上一章唠叨了关于表的一些基本操作,但是忽略了一个非常重要的东西 —— 列的属性。不过在介绍列的属性之前,我们应该先稍微了解一点查询表中的记录和向表中插入记录的简单语句。
简单的查询和插入的语句
简单的查询语句
如果我们想查看某个表里已经存储了哪些数据,可以用下边这个语句:
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
,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行记录就插入成功了!
列的属性
我们在上一章唠叨表结构的时候说表中的每个列都可以有一些属性,至于这些属性是什么以及怎么在创建表的时候把它们定义出来就是本章接下来的内容哈。不过我们之后还会用到first_table
表做示例,所以先把该表删掉:
mysql> DROP TABLE first_table;
Query OK, 0 rows affected (0.01 sec)
默认值
我们刚说过在书写INSERT
语句插入记录的时候可以只指定部分的列,那些没有被显式指定的列的值将被设置为NULL
,换一种说法就是列的默认值为NULL
,NULL
的含义是这个列的值还没有被设置。如果我们不想让默认值为NULL
,而是设置成某个有意义的值,可以在定义列的时候给该列增加一个DEFAULT
属性,就像这样:
列名 列的类型 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'
);
这个从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>
NOT NULL属性
有时候我们需要要求表中的某些列中必须有值,不能存放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>
看到报了个错,提示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>
可以看到执行结果提示我们first_column
并没有设置默认值,所以在使用INSERT
语句插入记录的时候不能省略掉这个列的值。
主键
有时候在我们的表里可以通过某个列或者某些列确定唯一的一条记录,我们就可以把这个列或者这些列称为候选键
。比如在学生信息表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>
所以大家在插入数据的时候至少别忘了给主键列赋值哈~
UNIQUE属性
对于不是主键的其他候选键,如果也想让MySQL
在我们向表中插入新记录的时候帮助我们校验一下某个列或者列组合的值是否重复,那么我们可以把这个列或列组合添加一个UNIQUE
属性,表明该列或者列组合的值是不允许重复的。与我们在建表语句中声明主键的方式类似,为某个列声明UNIQUE
属性的方式也有两种:
如果我们想为单个列声明
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
);
我们也可以把
UNIQUE
属性的声明单独提取出来,用这样的形式声明:UNIQUE [约束名称] (列名1, 列名2, ...)
或者:
UNIQUE KEY [约束名称] (列名1, 列名2, ...)
其实每当我们为某个列添加了一个`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)
);
可以看到,我们给这个`UNIQUE`约束起的名儿就是`uk_id_number`。
不过值得注意的是,对于多个列的组合具有`UNIQUE`属性的情况,必须使用这种单独声明的形式。
如果表中为某个列或者列组合定义了UNIQUE
属性的话,MySQL
会对我们插入的记录做校验,如果新插入记录在该列或者列组合的值已经在表中存在了,那就会报错!
主键和UNIQUE
约束的区别
主键和UNIQUE
约束都能保证某个列或者列组合的唯一性,但是:
一张表中只能定义一个主键,却可以定义多个
UNIQUE
约束!规定:主键列不允许存放NULL,而声明了
UNIQUE
属性的列可以存放NULL
,而且NULL
可以重复地出现在多条记录中!
小贴士: 一个表的某个列声明了UNIQUE属性,那这个列的值不就不可以重复了么,为啥NULL这么特殊?哈哈,NULL就是这么特殊。NULL其实并不是一个值,它代表不确定,我们平常说某个列的值为NULL,意味着这一列的值尚未被填入。
外键
插入到学生成绩表student_score
中的number
(学号)列中的值必须能在学生基本信息表student_info
中的number
列中找到,否则如果一个学号只在成绩表里出现,而在基本信息表里找不到相应的记录的话,就相当于插入了不知道是哪个学生的成绩,这显然是荒谬的。为了防止这样荒谬的情况出现,MySQL
给我们提供了外键约束机制。定义外键的语法是这样的:
CONSTRAINT [外键名称] FOREIGN KEY(列1, 列2, ...) REFERENCES 父表名(父列1, 父列2, ...);
其中的外键名称
也是可选的,一个名字而已,我们不自己命名的话,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)
);
这样,在对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
比如我们想在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>
先把原来的表删掉,然后在新表中增加了一个非负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>
可以看到,列id
是从1开始递增的。在为列定义AUTO_INCREMENT
属性的时候需要注意这几点:
一个表中最多有一个具有AUTO_INCREMENT属性的列。
具有AUTO_INCREMENT属性的列必须建立索引。主键和具有
UNIQUE
属性的列会自动建立索引。不过至于什么是索引,在学习MySQL进阶的时候才会介绍。拥有AUTO_INCREMENT属性的列就不能再通过指定DEFAULT属性来指定默认值。
一般拥有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 '第一个表';
影响展示外观的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>
我们在zerofill_table
表中创建了两个无符号整数列,不同的是i1
列具有ZEROFILL
属性,下边我们为这个表插入一条记录:
mysql> INSERT INTO zerofill_table(i1, i2) VALUES(1, 1);
Query OK, 1 row affected (0.00 sec)
mysql>
然后我们使用查询语句来展示一下刚插入的数据:
mysql> SELECT * FROM zerofill_table;
+------------+------+
| i1 | i2 |
+------------+------+
| 0000000001 | 1 |
+------------+------+
1 row in set (0.00 sec)
mysql>
对于具有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>
可以看到,其实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>
新创建的表中,i1
字段的显示宽度是5,所以最后的显示结果中补了4个0。不过在使用ZEROFILL
属性时应该注意下边几点:
在展示查询结果时,某列数据自动补0的条件有这几个:
- 该列必须是整数类型的
- 该列必须有
UNSIGNED ZEROFILL
的属性 - 该列的实际值的位数必须小于显示宽度
在创建表的时候,如果声明了
ZEROFILL
属性的列没有声明UNSIGNED
属性,那MySQL
会为该列自动生成UNSIGNED
属性。也就是说如果我们创建表语句是这样的:
CREATE TABLE zerofill_table (
i1 INT ZEROFILL,
i2 INT UNSIGNED
);
`MySQL`会自动帮我们为`i1`列加上`UNSIGNED`属性,也就是这样:
CREATE TABLE zerofill_table (
i1 INT UNSIGNED ZEROFILL,
i2 INT UNSIGNED
);
也就是说`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>
只有列的实际值的位数小于显示宽度时才会补0,实际值的位数大于显示宽度时照原样输出。
比方说我们刚刚把
12345678
存到了i1
列里,在展示这个值时,并不会截短显示的数据,而是照原样输出:mysql> SELECT * FROM zero_table;
+----------+----------+
| i1 | i2 |
+----------+----------+
| 00001 | 1 |
| 12345678 | 12345678 |
+----------+----------+
2 rows in set (0.00 sec)
mysql>
对于没有声明
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>
可以看到:
NULL
列代表该列是否可以存储NULL
,值为NO
时,表示不允许存储NULL
,值为YES
是表示可以存储NULL
。Key
列存储关于所谓的键
的信息,当值为PRI
是PRIMARY KEY
的缩写,代表主键;UNI
是UNIQUE KEY
的缩写,代表UNIQUE
属性。Default
列代表该列的默认值。Extra
列展示一些额外的信息。比方说如果某个列具有AUTO_INCREMENT
属性就会被展示在这个列里。
标识符的命名
像数据库名、表名、列名、约束名称或者我们之后会遇到的别的名称,这些名称统统被称为标识符
。虽然MySQL
中对标识符
的命名没多少限制,但是却不欢迎下边的这几种命名:
名称中全都是数字。
因为在一些
MySQL
语句中也会使用到数字,如果你起的名称中全部都是数字,会让MySQL
服务器分别不清哪个是名称,哪个是数字了。比如名称1234567
就是非法的。名称中有空白字符
MySQL
命令是靠空白字符来分隔各个单词的,比如下边这两行命令是等价的:CREATE DATABASE xiaohaizi;
CREATE DATABASE xiaohaizi;
但是如果你定义的名称中有空白字符,这样会被当作两个词去处理,就会造成歧义。比如名称`word1 word2 word3`就是非法的。
名称使用了
MySQL
中的保留字比方说
CREATE
、DATABASE
、INT
、DOUBLE
、DROP
、TABLE
等等这些单词,这些单词都是供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语言的规范吧,就是用小写字母、数字、下划线、美元符号等作为名称,如果有多个单词的话,各个单词之间用下划线连接起来,比如student
、student_info
啥的~