列的属性
简单的查询和插入语句
简单的查询语句
如果我们想查看某个表里已经存储了哪些数据,可以用下边这个语句:
SELECT * FROM 表名;
- 举例
mysql> SELECT * FROM first_table;
Empty set (0.01 sec)
mysql>
很遗憾,我们从来没有向表中插入过数据,所以查询结果显示的是 Empty set,表示什么都没查出来~
简单的插入语句
如果我们想向表中插入数据,可以用下边这个语句:
INSERT INTO 表名 (列1, 列2, 列3, ...) VALUES (值1, 值2, 值3, ...);
- 举例
mysql> INSERT INTO first_table (first_column) VALUES (2);
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO first_table (second_column) VALUES ('ccc');
Query OK, 1 row affected (0.01 sec)
这两句的意思就是
第一条插入语句我们只指定了 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 |
+--------------+---------------+
| 2 | NULL |
| NULL | ccc |
+--------------+---------------+
2 rows in set (0.00 sec)
mysql>
列的属性
我们在上一章唠叨表结构的时候说表中的每个列都可以有一些属性,至于这些属性是什么以及怎么在创建表的时候把它们定义出来就是本章接下来的内容哈。不过我们之后还会用到 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'
);
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) NOT NULL 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 语句插入记录的时候不能省略掉这个列的值。
主键
主键 == 唯一
主键可以是一个列,也可以是多个列合并,但是必须保证唯一性
一个表最多只能有一个主键,主键的值不能重复
通过主键可以找到唯一的一条记录。
如果我们的表中有定义主键的需求可以选用下边这两种方式之一来指定主键:
- 如果我们希望指定一个列为主键,可以在列定义的时候加上
PRIMARY KEY
关键字,比如这样:
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
);
- 也可以创建表的时候最后一行加入(多列组成的主键唯一的方式)
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 [约束名称] (列名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 约束的区别
- 一张表中只能定义一个主键,却可以定义多个 UNIQUE 约束!
- 规定:主键列不允许存放 NULL,而声明了 UNIQUE 属性的列可以存放 NULL,而且 NULL 可以重复地出现在多条记录中!
小贴士:
一个表的某个列声明了UNIQUE属性,那这个列的值不就不可以重复了么,为啥NULL这么特殊?哈哈,NULL就是这么特殊。NULL其实并不是一个值,它代表不确定,我们平常说某个列的值为NULL,意味着这一列的值尚未被填入。
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
属性的时候需要注意这几点:
INFO
一个表中只能有一个列被定义成
AUTO_INCREMENT
属性,而且这个列必须被定义成PRIMARY KEY
或者UNIQUE
约束,否则 MySQL 会报错。AUTO_INCREMENT
属性的列的数据类型必须是整数类型或者浮点数类型。AUTO_INCREMENT
属性的列不能通过DEFAULT
来指定默认值
列的注释
上一章中我们说了在建表语句的末尾可以添加 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 '第一个表';
一个列同时具有多个属性
每个列可以同时具有多个属性,属性声明的顺序无所谓,各个属性之间用空白隔开就好了~
小贴士:
注意,有的属性是冲突的,一个列不能具有两个冲突的属性,。如一个列不能既声明为PRIMARY KEY,又声明为UNIQUE KEY,不能既声明为DEFAULT NULL,又声明为NOT NULL。大家在使用过程中需要注意这一点。
外键(一般定义的时候不写)
插入到学生成绩表 student_score
中的 number
(学号)列中的值必须能在学生基本信息表 student_info
中的 number
列中找到,否则如果一个学号只在成绩表里出现,而在基本信息表里找不到相应的记录的话,就相当于插入了不知道是哪个学生的成绩,这显然是荒谬的。为了防止这样荒谬的情况出现,MySQL 给我们提供了外键约束机制。定义外键的语法是这样的:
INFO
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 表中找到,如果找不到则会报错。
标识符的命名
像数据库名、表名、列名、约束名称或者我们之后会遇到的别的名称,这些名称统统被称为标识符
。虽然 MySQL 中对标识符的命名没多少限制,但是却不欢迎下边的这几种命名:
- 名称中全都是数字
因为在一些 MySQL
语句中也会使用到数字,如果你起的名称中全部都是数字,会让 MySQL
服务器分别不清哪个是名称,哪个是数字了。比如名称 1234567
就是非法的。
- 名称中有空白字符
MySQL
命令是靠空白字符来分隔各个单词的,比如下边这两行命令是等价的:
CREATE DATABASE test;
CREATE DATABASE test;
但是如果你定义的名称中有空白字符,这样会被当作两个词去处理,就会造成歧义。比如名称 word1 word2 word3 就是非法的
- 名称使用了
MySQL
中的保留字
比方说 CREATE、DATABASE、INT、DOUBLE、DROP、TABLE 等等这些单词,这些单词都是供 MySQL 内部使用的,称之为保留字。如果你自己定义的名称用到了这些词儿也会导致歧义。比如名称 create 就是非法的。
INFO
虽然某些名称可能会导致歧义,但是如果你坚持要使用的话,也不是不行,你可以使用反引号来将你定义的名称扩起来,这样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 啥的~