约束的作用是保证数据的正确性和一至性,它是在mysql层面来实现的(它是mysql的功能/对象)。其实数据的正确性和一致是开发人员和DBA人员一起来实现的。约束只是保证数据正确性和一至性的一个方面。约束分为以下几类:
非空约束(not null) 字段级别上指定
默认约束(default) 字段级别上指定
自增约束(auto_increment) 字段级别上指定
唯一约束(unique key) 字段级别上指定
主键约束(primary key) 字段级别上指定
外键约束(foreign key) 从表/子表的字段级别上指定,此篇博文不会涉及,请看 https://blog.csdn.net/weixin_43733154/article/details/107961396
#### 数据库版本和当前MySQL实例默认的存储引擎
mysql> select @@version,@@global.default_storage_engine;
+------------+---------------------------------+
| @@version | @@global.default_storage_engine |
+------------+---------------------------------+
| 5.7.28-log | InnoDB |
+------------+---------------------------------+
1 row in set (0.00 sec)
#### 查看事务在当前会话下和全局下的提交方式是否为自动提交
mysql> select @@global.autocommit,@@autocommit;
+---------------------+--------------+
| @@global.autocommit | @@autocommit |
+---------------------+--------------+
| 1 | 1 |
+---------------------+--------------+
1 row in set (0.00 sec)
#### 会话模式下和全局模式下的SQL模式(是否包含严格模式STRICT_TRANS_TABLES)
mysql> select @@sql_mode\G
*************************** 1. row ***************************
@@sql_mode:
STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,
NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
1 row in set (0.00 sec)
mysql> select @@global.sql_mode\G
*************************** 1. row ***************************
@@global.sql_mode:
STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,
NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
1 row in set (0.00 sec)
#### 创建binbin库,并进入到binbin库下面;
create database if not exists binbin character set utf8 collate utf8_general_ci;
use binbin;
select database();
01:是在表的字段级别上进行指定,不用管字段的数据类型是什么;
02:一张表可以有多个字段拥有非空约束,其创建方法如下所示:
A:第一种:创建表时在相应的字段指定not null
B:第二种:表创建后用alter table 表名 modify ....; 来修改相关字段的属性;
C:注意:用第二种方法时,若相关字段的值有空值时则指定不会成功;
03:字段指定了非空约束(not null)
A:sql_mode开启了严格模式,插入数据时不为字段指定值,会直接报错;
B:sql_mode未开启严格模式,插入数据时不为字段指定值,不报错,该字段显示空值(不是用null来表示的哈)
04:字段未指定非空约束(not null)
A:此时不管你的sql_mode有没有开启严格模式;
B:不为字段指定值时,不会报错,默认用空值(是用null来表示的哈)表示;
在创建表时就为相关字段指定非空约束
#### 创建test22_1表
create table if not exists test22_1(
name varchar(20) not null comment"姓名", # 为name字段指定了非空约束(not null)
sex varchar(20) not null comment"性别" # 为sex字段指定了非空约束(not null)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表22_1";
#### 查看test22_1表的表结构
mysql> desc test22_1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| sex | varchar(20) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
表创建成功后(没有任何数据),给相关字段进行添加
#### 创建test22_2表,在创建表时不为name、sex字段指定非空约束
create table if not exists test22_2(
name varchar(20) comment"姓名", # 没有为name字段指定非空约束(not null)
sex varchar(20) comment"性别" # 没有为sex字段指定非空约束(not null)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表22_2";
#### 查看test22_2表的表结构
mysql> desc test22_2;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(20) | YES | | NULL | |
| sex | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
#### 修改test22_2表中的name字段和sex字段拥有非空约束
mysql> select count(*) from test22_2 where name is null; # 注意哈:test22_2表中没有任何的数据哈
+----------+
| count(*) |
+----------+
| 0 |
+----------+
1 row in set (0.00 sec)
## PS:以下命令在修改test22_2表中name字段和sex字段的属性前,你应该先看一看表(test22_2)的创建语句
## show create table test22_2;
mysql> alter table test22_2 modify name varchar(20) not null comment"姓名";
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table test22_2 modify sex varchar(20) not null comment"性别";
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc test22_2; # 查看test22_2表的表结构
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| sex | varchar(20) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
创建表且给相应字段指定非空约束
#### 创建test23表
create table if not exists test23(
name varchar(20) not null comment"姓名", # 指定了非空约束(not null)
sex varchar(20) not null comment"性别" # 指定了非空约束(not null)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表23";
#### 查看test23表的表结构
mysql> desc test23;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| sex | varchar(20) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec) ^==no表示具备非空约束(not null)
sql_mode中包含严格模式的情况下插入数据
#### 会话模式下SQL_MODE开启了严格模式
set session sql_mode="strict_trans_tables";
select @@sql_mode;
#### 往test23表中插入数据(给name字段指定数据,不给sex字段指定数据)
mysql> insert into test23(name) values("chenliang");
ERROR 1364 (HY000): Field 'sex' doesn't have a default value <==直接报错
mysql> select * from test23;
Empty set (0.01 sec)
sql_mode中未开启严格模式的情况下插入数据
#### 修改当前会话模式下sql_mode中不包含严格模式
set session sql_mode="";
select @@sql_mode;
#### 往test23表中插入数据(给name字段指定数据,不给sex字段指定数据)
mysql> insert into test23(name) values("chenliang");
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from test23;
+-----------+-----+
| name | sex |
+-----------+-----+
| chenliang | | <== sex字段是空值(不会用null来表示)
+-----------+-----+
1 row in set (0.00 sec)
#### 查询出test23表中sex为空(不是用null来表示的)的记录
mysql> select * from test23 where sex="";
+-----------+-----+
| name | sex |
+-----------+-----+
| chenliang | |
+-----------+-----+
1 row in set (0.00 sec)
#### 将当前会话模式下的sql_mode修改回源样(即包含严格模式)
mysql> set session sql_mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION";
Query OK, 0 rows affected (0.00 sec)
创建test24表,相应字段不具备非空约束(not null)
#### 创建test24表
create table if not exists test24(
name varchar(20) comment"姓名", # 没有指定非空约束(not null)哈
sex varchar(20) comment"性别" # 没有指定非空约束(not null)哈
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表24";
#### 查看test24表的表结构可以看到name字段的属性为非空约束,sex字段没有指定非空约束
mysql> desc test24;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(20) | YES | | NULL | |
| sex | varchar(20) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
往test24表中插入数据(不用管sql_mode有没有开启严格模式)
#### 往test24表中插入数据(给name字段指定数据,不给sex字段指定数据)
mysql> insert into test24(name) values("chenliang");
Query OK, 1 row affected (0.00 sec)
mysql> select * from test24;
+-----------+------+
| name | sex |
+-----------+------+
| chenliang | NULL | <== sex字段是用NULL来表示的是为空值
+-----------+------+
1 row in set (0.00 sec)
#### 查询test24表中sex字段为空(用null来表示的)的记录
mysql> select * from test24 where sex is null;
+-----------+------+
| name | sex |
+-----------+------+
| chenliang | NULL |
+-----------+------+
1 row in set (0.00 sec)
#### 创建test25表
create table if not exists test25(
id int unsigned auto_increment comment"序列",
name varchar(20) comment"姓名", # name字段没有指定非空约束哈
sex varchar(20) not null comment"性别",
primary key(id)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表25";
#### 查看test25表的表结构
mysql> desc test25;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| sex | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
#### 插入几条测试数据
-- 正常插入数据
insert into test25(name,sex) values("chenliang01","男");
insert into test25(name,sex) values("chenliang02","男");
insert into test25(name,sex) values("chenliang03","男");
-- 没有往name字段插入数据
insert into test25(sex) values("女");
-- 正常插入数据
insert into test25(name,sex) values("chenliang05","女");
insert into test25(name,sex) values("chenliang06","女");
-- 没有往name字段插入数据
insert into test25(sex) values("男");
-- 正常插入数据
insert into test25(name,sex) values("chenliang08","男");
insert into test25(name,sex) values("chenliang09","男");
#### 查看test25表中的所有数据
mysql> select * from test25;
+----+-------------+-----+
| id | name | sex |
+----+-------------+-----+
| 1 | chenliang01 | 男 |
| 2 | chenliang02 | 男 |
| 3 | chenliang03 | 男 |
| 4 | NULL | 女 | <==name字段有空值
| 5 | chenliang05 | 女 |
| 6 | chenliang06 | 女 |
| 7 | NULL | 男 | <==name字段有空值
| 8 | chenliang08 | 男 |
| 9 | chenliang09 | 男 |
+----+-------------+-----+
9 rows in set (0.00 sec)
#### 此时你为name添加非空约束时会报错
mysql> alter table test25 modify name varchar(20) not null comment"姓名";
ERROR 1138 (22004): Invalid use of NULL value
#### 查询出哪些记录中name字段为空值
mysql> select * from test25 where name is null;
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 4 | NULL | 女 |
| 7 | NULL | 男 |
+----+------+-----+
2 rows in set (0.00 sec)
你可能会想到,如果我修改当前会话下的sql_mode中不包括严格模式,然后就直接alter进行
为name字段添加非空约束,能不能句成功,答案是可以成功的,当成功后,id等于4和7的记
录就会变成如下所示:你可以用select * from test25 where name="";来查询出来
+----+------+-----+
| id | name | sex |
+----+------+-----+
| 4 | | 女 |
| 7 | | 男 |
+----+------+-----+
#### 用update更新第id等于4和id等于7记录中name字段的值为"null+1",要加条件哈,我这张表的id字段是主键字段的哈
update
test25
set
name="null+1"
where
id in(4,7) and name is null;
mysql> select * from test25 where name is null;
Empty set (0.00 sec)
#### 用alter命令给test25表的name字段添加上非空约束
mysql> show create table test25\G # 查看test25表的创建语句,用得着
*************************** 1. row ***************************
Table: test25
Create Table: CREATE TABLE `test25` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '序列',
`name` varchar(20) DEFAULT NULL COMMENT '姓名',
`sex` varchar(20) NOT NULL COMMENT '性别',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='测试表25'
1 row in set (0.00 sec)
mysql> alter table test25 modify name varchar(20) not null COMMENT '姓名';
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc test25;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | | <==name字段已经具有非空约束
| sex | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
01:它是在表的字段级别上进行指定,一张表中允许多个字段拥有默认约束(default);
02:当为字段指定默认约束的值时,需要根据字段的数据类型来指定,默认约束的值必须得是一个确认的值或者是变量(不是函数哈);
03:字段没有指定非空约束(not null),不管字段是啥数据类型,不管sql_mode有没有开启严格模式,插入的时候不给字段指定值,
默认值为空(用NULL来表示)
## 创建test32表
create table if not exists test32(
name varchar(20) not null comment"姓名",
sex enum("男","女") default"男" comment"性别" # 默认值为"男"
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表32";
## 查看test32表的表结构
mysql> desc test32;
+-------+-------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| sex | enum('男','女') | YES | | 男 | |
+-------+-------------------+------+-----+---------+-------+
2 rows in set (0.01 sec) <==name字段没有指定非空约束 <==name字段默认值为"男"
## 往test32表中插入数据(给name指定数据,不给sex字段指定数据)
mysql> insert into test32(name) values("chenliang");
Query OK, 1 row affected (0.00 sec)
mysql> select * from test32;
+-----------+------+
| name | sex |
+-----------+------+
| chenliang | 男 | <== sex字段的值默认就是"男"
+-----------+------+
1 row in set (0.00 sec)
## 创建test33表
create table if not exists test33(
name varchar(20) not null comment"姓名",
vip set("vip1","vip2","vip3") default"vip1" comment"会员" # 默认值为"vip1"
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表33";
## 查看test33表的表结构
mysql> desc test33;
+-------+---------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------------+------+-----+---------+-------+
| name | varchar(20) | NO | | NULL | |
| vip | set('vip1','vip2','vip3') | YES | | vip1 | |
+-------+---------------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
## 往test33表中插入数据(给name字段指定数据,不给vip字段指定数据)
mysql> insert into test33(name) values("chenliang01");
Query OK, 1 row affected (0.01 sec)
mysql> select * from test33;
+-------------+------+
| name | vip |
+-------------+------+
| chenliang01 | vip1 | <== 没往vip字段插入数据,但vip字段默认值为vip1
+-------------+------+
1 row in set (0.00 sec)
## 创建test34表
create table if not exists test34(
name varchar(20) not null comment"姓名",
t_time datetime default current_timestamp comment"时间" # 默认值是变量current_timestamp
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表34";
## 查看test34表的表结构
mysql> desc test34;
+--------+-------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+-------------------+-------+
| name | varchar(20) | NO | | NULL | |
| t_time | datetime | YES | | CURRENT_TIMESTAMP | |
+--------+-------------+------+-----+-------------------+-------+
2 rows in set (0.00 sec) <==t_time字段没指定非空约束,默认值为current_timestamp变量
## 往test34表中的name字段插入数据,不往t_time字段插入数据,
mysql> insert into test34(name) values("chenliang");
Query OK, 1 row affected (0.00 sec)
mysql> select * from test34;
+-----------+---------------------+
| name | t_time |
+-----------+---------------------+
| chenliang | 2020-04-28 09:15:03 | <==t_time的数据以你的系统时间为准的
+-----------+---------------------+
1 row in set (0.00 sec)
01:是在表的字段级别上进行指定,一张表中只能有一个自增字段;常用于表的"序列"字段中;
02:自增约束(auto_increment)的字段的数据类型必须得为整型,但不是都适合;
A:整型数据类型有:tinyint、smallint、mediumint、int、integer、bigint
B:因为auto_increment默认是从1开始自增,所以只需要关注每类整型数据的无符号范围
C:又因为生产的数据表中可能有很多的数据,若有自增列,则列的数据类型应该为int或bigint整型数据类型
03:当字段的数据类型为int或bigint时,auto_increment的最大值是多少呢?
A:字段数据类型:int unsigned auto_increment最大值:4294967295(就是int无符号下的最大值)
B:字段数据类型:bigint unsigned auto_increment最大值:18446744073709551615(就是bigint无符号下的最大值)
C:当数据类型为int或bigint时,auto_increment的最大值就是它们的“无符号”范围,不包括0,因为auto_increment是从1开始自增
04:站在自增约束的角度来说:拥有自增约束的字段的值必须得唯一,但自增约束不包含让其唯一性的功能,只有自增的功能,
所以需要配合key(primary或unique)使用,但我们通常让其配合主键key来使用。若没有配合key使用,会报如下的错误:
ERROR 1075 (42000): Incorrect table definition; there can be only one auto
column and it must be defined as a key
05:我们也可以指定某一张表的自增字段下一次从哪个值开始自增
A:当然你要知道当前表的自增字段已经自增到哪了;
B:用alter进行修改:alter table 表名 auto_increment=整数(大于A步骤得到的值)
06:auto_increment为何默认是从1开始自增的;
auto_increment_offset=1
# 表示第一次自增时,从1开始,该参数的值不能大于auto_increment_increment的值
auto_increment_increment=1
# 表示第一次自增后,每次自增时步长多少,
PS1:以上两个参数可在线修改,修改后会对已存在的表(含自增)和新创建的表(含自增)有影响
示例1:在线修改auto_increment_offset=1 auto_increment_increment=2
01:之前的表(含自增),自增字段目前已经自增到40了
A:下次自增就应该是41
B:第二次自增43
C:第三次自增45
D:以此类推
02:新创建的表(含自增)
A:第一次自增是1
B:第二次自增是3
C:第三次自增是5
D:以准类推;
mysql> create table if not exists test42(
-> id int unsigned auto_increment comment"序列",
-> name varchar(20) not null comment"姓名"
-> )engine=innodb character set utf8 collate utf8_general_ci comment"测试表42";
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column
and it must be defined as a key
## 报错翻译:表定义不正确;只能有一个自动列,必须将其定义为键
## 报错原因:test42表的id字段没有添加key;
## 创建test43表
create table if not exists test43(
id int unsigned auto_increment comment"序列", # 指定了自增约束的哈
name varchar(20) not null comment"姓名",
primary key(id) # 指定了id字段为主键key
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表43";
## 查看test43表的表结构
mysql> desc test252;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
## 站点在索引的角色去看PRI
mysql> show index from test43\G
*************************** 1. row ***************************
Table: test43
Non_unique: 0
Key_name: PRIMARY <==key名为primary,可以得知是主键key
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
## 站在约束的角度去看PRI
select
table_schema as "库名",
table_name as "表名",
column_name as "字段名",
constraint_name as "约束名"
from
information_schema.key_column_usage
where table_schema="binbin" and table_name="test43";
+--------+--------+-----------+-----------+
| 库名 | 表名 | 字段名 | 约束名 |
+--------+--------+-----------+-----------+
| binbin | test43 | id | PRIMARY |
+--------+--------+-----------+-----------+
1 row in set (0.00 sec)
## 往test43表中插入两条数据,不指定往id列插入数据
mysql> insert into test43(name) values("chenliang01"),("chenliang02");
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from test43;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
+----+-------------+
2 rows in set (0.00 sec)
## 查看test43表的id字段下一次自增的是到哪个数值
mysql> show table status from binbin where name="test43"\G
*************************** 1. row ***************************
Name: test43
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 2
Avg_row_length: 8192
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 3 <==下一次应该自增到3
Create_time: 2020-04-28 10:03:42
Update_time: 2020-04-28 10:07:52
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment: 测试表43
1 row in set (0.00 sec)
## 再往43表中插入一条数据,不指定id列,看其是否是自增到3
mysql> insert into test43(name) values("chenliang03");
Query OK, 1 row affected (0.00 sec)
mysql> select * from test43;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
| 3 | chenliang03 |
+----+-------------+
3 rows in set (0.00 sec)
## 其实也可以指定id字段的值,但你指定的值一定是得大于它下次自增的值,但不这样干
mysql> insert into test43(id,name) values(5,"chenliang05");
Query OK, 1 row affected (0.01 sec)
mysql> select * from test43;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
| 3 | chenliang03 |
| 5 | chenliang05 | <==5是我们指定的,它比3大,所以成功,下一次自增的就该是到6了
+----+-------------+
4 rows in set (0.00 sec)
## 创建test44表
create table if not exists test44(
id int unsigned not null auto_increment unique comment"序列",
# id字段指定了自增约束和uniquekey的哈
name varchar(20) not null comment"姓名"
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表44";
## 查看test44表的表结构
mysql> desc test44;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
## PRI:从mysql角度来说,就是主键,但不是我们用priamry key指定的,因为表中我们没有用primary key指定,但
## 我们为id字段指定了not null和auto_increment(自增嘛,肯定不会重复),且因为表是innodb存储引擎,把以
## 它会把id字段认为是主键字段;
## 站点在索引的角度去看PRI
mysql> show index from test44\G
*************************** 1. row ***************************
Table: test44
Non_unique: 0
Key_name: id <==key名为id
Seq_in_index: 1
Column_name: id <==字段名:id
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
## 站在约束的角度看一看PRI
select
table_schema as "库名",
table_name as "表名",
column_name as "字段名",
constraint_name as "约束名"
from
information_schema.key_column_usage
where table_schema="binbin" and table_name="test44";
+--------+--------+-----------+-----------+
| 库名 | 表名 | 字段名 | 约束名 |
+--------+--------+-----------+-----------+
| binbin | test44 | id | id |
+--------+--------+-----------+-----------+
1 row in set (0.00 sec)
## 往test44表中插入两条数据,不指定往id列插入数据
mysql> insert into test44(name) values("chenliang01"),("chenliang02");
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from test44;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
+----+-------------+
2 rows in set (0.00 sec)
## 查看test44表id字段下一次自增的是到哪个数值
mysql> show table status from binbin where name="test44"\G
*************************** 1. row ***************************
Name: test44
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 2
Avg_row_length: 8192
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 3 <==下次自增到3
Create_time: 2020-04-28 10:14:02
Update_time: 2020-04-28 10:18:58
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment: 测试表44
1 row in set (0.00 sec)
## 再往test44表中插入一条数据,不指定id列,看其是否是自增到3
mysql> insert into test44(name) values("chenliang03");
Query OK, 1 row affected (0.00 sec)
mysql> select * from test44;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
| 3 | chenliang03 |
+----+-------------+
3 rows in set (0.00 sec)
## 其实也可以指定id字段的值,但你指定的值一定是得大于它下次自增的值,但不这样干
mysql> insert into test44(id,name) values(5,"chenliang05");
Query OK, 1 row affected (0.00 sec)
mysql> select * from test44;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
| 3 | chenliang03 |
| 5 | chenliang05 | <==5是我们指定的,它比3大,所以成功,下一次自增的就该是到6了
+----+-------------+
4 rows in set (0.00 sec)
## 创建test45表
create table if not exists test45(
id bigint unsigned auto_increment comment"序列", # 指定了自增约束的哈
name varchar(20) not null comment"姓名",
primary key(id) # 指定了id字段为主键key
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表45";
## 查看test45表的表结构
mysql> desc test45;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
## 往test45表中插入几条测试数据
mysql> insert into test45(name) values("chenliang01"),("chenliang02"),("chenliang03");
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from test45;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
| 3 | chenliang03 |
+----+-------------+
3 rows in set (0.00 sec)
## 查看test45下次自增是到哪
mysql> show table status from binbin where name="test45"\G
*************************** 1. row ***************************
Name: test45
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 3
Avg_row_length: 5461
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 4 <==下次应该自增到4,后面我们让其从40开始自增
Create_time: 2020-04-28 10:39:12
Update_time: 2020-04-28 10:41:35
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment: 测试表45
1 row in set (0.00 sec)
## 修改test45表的自增字段下次从40开始自增
mysql> alter table test45 auto_increment=40;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show table status from binbin where name="test45"\G
*************************** 1. row ***************************
Name: test45
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 3
Avg_row_length: 5461
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 40 <==下次自增字段就应该是从40开始
Create_time: 2020-04-28 10:45:18
Update_time: 2020-04-28 10:41:35
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment: 测试表45
1 row in set (0.00 sec)
## 往test45表中插入一条数据,不给id字段指定值,看是不是从40开始自增
mysql> select * from test45;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
| 3 | chenliang03 |
+----+-------------+
3 rows in set (0.00 sec)
mysql> insert into test45(name) values("chenliang40");
Query OK, 1 row affected (0.00 sec)
mysql> select * from test45;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
| 3 | chenliang03 |
| 40 | chenliang40 |
+----+-------------+
4 rows in set (0.00 sec)
## 创建test46表
create table if not exists test46(
id bigint unsigned auto_increment comment"序列", # 指定了自增约束的哈
name varchar(20) not null comment"姓名",
primary key(id) # 指定了主键key的哈
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表46";
## 查看test46表的表结构
mysql> desc test46;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
## 查看test46表下次从哪个数值开始自增
mysql> show table status from binbin where name="test46"\G
*************************** 1. row ***************************
Name: test46
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 1 <==自增字段下次是从1开始自增的
Create_time: 2020-04-28 10:50:35
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment: 测试表46
1 row in set (0.00 sec)
## 为什么auto_increment默认是人1开始自增的呢?
mysql> show variables like "auto_in%";
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 1 | <==表示第二次自增时,跨1步,也就是2了,以此类推
| auto_increment_offset | 1 | <==表示第一次自增默认是从1开始
+--------------------------+-------+
2 rows in set (0.00 sec)
auto_increment_offset=1
# 表示auto_increment默认从哪个数值开始自增,默认是从1开始的
# 可以在线修改,修改后对之前的表(含有自增约束)和新创建的表(含自增)都有影响,
# 该参数的值不能大于auto_increment_increment的值;
auto_increment_increment=1
# 表示auto_increment自增时的步长(跨几步)
## 修改auto_increment_offset和auto_increment_increment变量后的理论
auto_increment_offset=1
auto_increment_increment=2;
自增就应该是:1,3,5,7,9.......
## 在线修改auto_increment_offset=1和auto_increment_increment=2;
mysql> set session auto_increment_offset=1;
Query OK, 0 rows affected (0.00 sec)
mysql> set session auto_increment_increment=2;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like "auto_in%";
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| auto_increment_increment | 2 |
| auto_increment_offset | 1 |
+--------------------------+-------+
2 rows in set (0.01 sec)
## 测试一下之前创建的表46会不会有变化,答案肯定是会有变化的
mysql> select * from test46;
Empty set (0.00 sec)
mysql> show table status from binbin where name="test46"\G
*************************** 1. row ***************************
Name: test46
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 0
Avg_row_length: 0
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: 1 <==自增字段下次是从1开始自增的
Create_time: 2020-04-28 11:22:04
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment: 测试表46
1 row in set (0.00 sec)
mysql> insert into test46(name) values("chenliang01"),("chenliang02");
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from test46;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 3 | chenliang02 |
+----+-------------+
2 rows in set (0.00 sec)
## 为了后面的实践,我们还是把auto_increment_offset和auto_increment_increment给修改
## 回源来的默认值
set session auto_increment_offset=1;
set session auto_increment_increment=1;
01:唯一约束其实就是唯一索引,是在表的字段级别上进行指定,一张表中可以有多个唯一约束;
02:仅仅站在唯一约束的角度来说:不能有重复值,但可以有空值(插入数据时不给字段指定值,用NULL来表示)
03:从现实的角度来说:拥有唯一约束的字段就可以允许空值嘛,不一定,得看你有没有在字段上另外加上非空约束。
04:唯一约束在创建时最好为其指定名称,以防止在删除时不小心删除了字段;
05:唯一约束的创建方法如下所示:
A:建表时在字段上进行指定,这里又有两种方法,如下所示
a: 例 tel bigint unsigned unique comment"电话" # 不推荐,约束名是字段名
b:例 tel bigint unsigned comment"电话", # 推荐,可以自定义名称
unique uni_tel(tel)
B:表创建成功后,用alter table 表名 modif.....来修改相关字段的属性,不建议用这种方法,无法进行唯一约束名称的指定
a:若表中没有任何数据,可以直接用alter命令进行字段的属性更改
b:若表中相关字段有重复值,你就得先处理,然后再用alter命令进行更改;
C:表创建成功后,用alter table 表名 add unique.......来添加唯一约束,建议用这种方法,可以自定义唯一约束的名称
a:若表中没有任何数据,可以直接用alter命令进行字段的属性更改
b:若表中相关字段有重复值,你就得先处理,然后再用alter命令进行更改;
06:唯一约束可以是在单个字段上进行创建
A:表中没有主键,你的字段有unique和not null,你用desc看到的是PRI,其实还是唯一约束
B:表中拥有主键,你的字段有unique和not null,你用desc看到的是UNI,还是唯一约束
C:表中拥有主键,你的字段有unique,你用desc看到的是UNI,还是唯一约束
07:唯一约束可以把多个字段联合起来进行创建,你用desc看到的是MUI
建表时为相应字段指定唯一约束(不指定约束名,默认以字段名为名)
## 创建test52_1表
create table if not exists test52_1(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名",
tel bigint unsigned unique comment"电话号码", # 指定了唯一约束,没有not null
primary key(id)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表test52_1";
## 查看test52_1表的表结构
mysql> desc test52_1;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | YES | UNI | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
## 站在索引的角度看一看UNI的名称是什么
mysql> show index from test52_1 where column_name="tel"\G
*************************** 1. row ***************************
Table: test52_1
Non_unique: 0
Key_name: tel <==key的名称
Seq_in_index: 1
Column_name: tel <==字段名
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
建表时为相应字段指定唯一约束(给唯一约束指定名称,不让其用字段的名称)
## 创建test52_2表
create table if not exists test52_2(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名",
tel bigint unsigned comment"电话号码", # 没有指定not null
primary key(id),
unique uni_tel(tel) # 指定tel有唯一约束,且命名为uni_tel
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表52_2";
## 查看test52_2表的表结构
mysql> desc test52_2;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | YES | UNI | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
## 站在索引的角度看一看UNI的名称是什么
mysql> show index from test52_2 where column_name="tel"\G
*************************** 1. row ***************************
Table: test52_2
Non_unique: 0
Key_name: uni_tel <==key名:uni_tel
Seq_in_index: 1
Column_name: tel <==字段名:tel
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
建表成功后再为相应的字段指定唯一约束
注意:表没任何数据,用alter table 表名 modify…;来添加
## 创建test52_3表
create table if not exists test52_3(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名",
tel bigint unsigned comment"电话号码", # 没有指定唯一约束和not null
primary key(id)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表test52_3";
## 查看test52_3表的表结构
mysql> desc test52_3;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | YES | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
## 为test52_3的tel字段添加上唯一约束(注意:表中是没有任何数据的哈)
mysql> show create table test52_3\G # 查看test52_3表的创建语句,后面有用
*************************** 1. row ***************************
Table: test52_3
Create Table: CREATE TABLE `test52_3` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '序列',
`name` varchar(30) NOT NULL COMMENT '姓名',
`tel` bigint(20) unsigned DEFAULT NULL COMMENT '电话号码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试表test52_3'
1 row in set (0.00 sec)
mysql> alter table test52_3 modify tel bigint(20) unsigned unique COMMENT '电话号码';
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc test52_3;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | YES | UNI | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec) ^==看这
mysql> show index from test52_3 where column_name="tel"\G
*************************** 1. row ***************************
Table: test52_3
Non_unique: 0
Key_name: tel <==key名:tel
Seq_in_index: 1
Column_name: tel <==列名:tel
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
建表成功后再为相应的字段指定唯一约束
注意:表没任何数据,用alter table 表名add unique 名称…;来添加
## 创建test52_4表
create table if not exists test52_4(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名",
tel bigint unsigned comment"电话号码", # 没有指定唯一约束和not null
primary key(id)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表52_4";
## 查看test52_4表的表结构
mysql> desc test52_4;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | YES | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
## 为test52_4表的tel字段添加唯一约束,唯一约束的名称为uni_tel(表中是没有数据的哈)
mysql> alter table test52_4 add unique uni_tel(tel);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc test52_4;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | YES | UNI | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec) ^==看这
mysql> show index from test52_4 where column_name="tel"\G
*************************** 1. row ***************************
Table: test52_4
Non_unique: 0
Key_name: uni_tel <== key名:uni_tel
Seq_in_index: 1
Column_name: tel <== 字段名:tel
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
## 创建test53表
create table if not exists test53(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名",
tel bigint unsigned comment"电话号码", # 没有指定not null
primary key(id),
unique uni_tel(tel) # 给tel字段指定了唯一约束,名称为uni_tel
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表53";
## 查看test53表的表结构
mysql> desc test53;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | YES | UNI | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
## 往test53表中插入数据,往tel字段插入重复值,看一看有什么效果
mysql> insert into test53(name,tel) values("chenliang01",18382021111);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test53(name,tel) values("chenliang02",18382022222);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test53;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382021111 |
| 2 | chenliang02 | 18382022222 |
+----+-------------+-------------+
2 rows in set (0.00 sec)
mysql> insert into test53(name,tel) values("chenliang03",18382022222);
ERROR 1062 (23000): Duplicate entry '18382022222' for key 'uni_tel'
^==报错了,tel字段重复了
## 往test53表中插入数据,不往tel字段插入数据
mysql> select * from test53;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382021111 |
| 2 | chenliang02 | 18382022222 |
+----+-------------+-------------+
2 rows in set (0.00 sec)
mysql> insert into test53(name) values("chenliang03");
Query OK, 1 row affected (0.00 sec)
mysql> select * from test53;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382021111 |
| 2 | chenliang02 | 18382022222 |
| 4 | chenliang03 | NULL | <==NULL表示空值,并不是值是NULL哈
+----+-------------+-------------+
3 rows in set (0.00 sec)
## 创建test54表
create table if not exists test54(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名", # 指定了非空约束
tel bigint unsigned not null comment"电话号码", # 指定了非空约束
primary key(id),
unique uni_name_tel(name,tel) # 将name和tel字段做联合唯一约束,名称为uni_name_tel
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表54";
## 查看test54表的表结构
mysql> desc test54;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | MUL | NULL | |
| tel | bigint(20) unsigned | NO | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
## 从索引角度查看test54表中MUL的信息
mysql> show index from test54 where key_name="uni_name_tel"\G
*************************** 1. row ***************************
Table: test54
Non_unique: 0 <==0表示唯一约束
Key_name: uni_name_tel <==key名:uni_name_tel
Seq_in_index: 1
Column_name: name <==字段名:name
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Table: test54
Non_unique: 0 <==0表示唯一约束
Key_name: uni_name_tel <==key名:uni_name_tel
Seq_in_index: 2
Column_name: tel <==字段名:tel
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
2 rows in set (0.00 sec)
## 往test54表中插入数据(让其出现重复值)
mysql> insert into test54(name,tel) values("chenliang01",18382024444);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test54(name,tel) values("chenliang01",18382024444);
ERROR 1062 (23000): Duplicate entry 'chenliang01-18382024444' for key 'uni_name_tel'
mysql> select * from test54;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024444 |
+----+-------------+-------------+
1 row in set (0.00 sec)
mysql> insert into test54(name,tel) values("chenliang01",18382025555);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test54;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024444 |
| 3 | chenliang01 | 18382025555 |
+----+-------------+-------------+
2 rows in set (0.00 sec)
我当前表中有个字段(tel)指定了唯一约束(unique)和非空约束(not ull),当前表中所有记录中的tel字段中没有重复值,但我现在要插入大量的数据(可能有重复值),怎么办?
## 创建test55表
create table if not exists test55(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名",
tel bigint unsigned not null comment"电话号码", # 指定了not null约束
primary key(id),
unique uni_tel(tel) # 指定了唯一约束,名称为uni_tel
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表55";
## 查看test55表的表结构
mysql> desc test55;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | NO | UNI | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
## 插入几条测试数据(tel字段没有重复值,所以都能成功)
insert into test55(name,tel) values
("chenliang01",18382024221),("chenliang02",18382024222),
("chenliang03",18382024223),("chenliang04",18382024224);
## 查看test55表中的所有数据(可以看出tel字段没有重复数据)
mysql> select * from test55;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024221 |
| 2 | chenliang02 | 18382024222 |
| 3 | chenliang03 | 18382024223 |
| 4 | chenliang04 | 18382024224 |
+----+-------------+-------------+
4 rows in set (0.00 sec)
ignore(忽略重复值,不影响后面的数据插入)
## 查看test55表中的所有数据
mysql> select * from test55;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024221 |
| 2 | chenliang02 | 18382024222 |
| 3 | chenliang03 | 18382024223 |
| 4 | chenliang04 | 18382024224 |
+----+-------------+-------------+
4 rows in set (0.00 sec)
## 我现在准备插入数据(注意:tel字段有重复值)
insert into test55(name,tel) values
("chenliang05",18382024223),
("chenliang06",18382024224),
("chenliang07",18382024226);
# ^==这条语句插入时,肯定会报错,没有任何一条数据到表中,这里不要执行它;
insert ignore into test55(name,tel) values
("chenliang05",18382024223),
("chenliang06",18382024224),
("chenliang07",18382024226);
# ^==这条语句执行时不会报错,但有警告,到表中的数据只有("chenliang07",18382024226);
mysql> select * from test55;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024221 |
| 2 | chenliang02 | 18382024222 |
| 3 | chenliang03 | 18382024223 |
| 4 | chenliang04 | 18382024224 |
| 5 | chenliang07 | 18382024226 |
+----+-------------+-------------+
5 rows in set (0.00 sec)
replace(先删除重复字段所在的记录,然后用新数据进行替换)
## 查看test55表中的所有数据(tel字段没有重复数据哈)
mysql> select * from test55;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024221 |
| 2 | chenliang02 | 18382024222 |
| 3 | chenliang03 | 18382024223 |
| 4 | chenliang04 | 18382024224 |
| 5 | chenliang07 | 18382024226 |
+----+-------------+-------------+
5 rows in set (0.00 sec)
## 我现在准备插入数据(注意:tel字段有重复值)
insert into test55(name,tel) values
("chenliang08",18382024224),
("chenliang09",18382024226),
("chenliang10",18382024230);
# ^==这条语句插入时,肯定会报错,没有任何一条数据到表中,这里不要执行它;
replace into test55(name,tel) values
("chenliang08",18382024224),
("chenliang09",18382024226),
("chenliang10",18382024230);
# ^==这条语句执行时不会报错,但有警告,
# 先把tel等于18382024224的记录删除掉,再把("chenliang08",18382024224)拿去替换
# 先把tel等于18382024226的记录删除掉,再把(”chenliang09",18382024226)拿去替换
# 最后插入("chenliang10",18382024230)数据;
mysql> select * from test55;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024221 |
| 2 | chenliang02 | 18382024222 |
| 3 | chenliang03 | 18382024223 |
| 8 | chenliang08 | 18382024224 |
| 9 | chenliang09 | 18382024226 |
| 10 | chenliang10 | 18382024230 |
+----+-------------+-------------+
6 rows in set (0.00 sec)
我当前表中的tel字段只指定了非空约束(not null),没有指定唯一约束(unique),现在tel字段中已经有重复的数据了,我现在在tel字段添加唯一约束(肯定失败),那么如何处理呢?
场景模拟
## 创建test56表
create table if not exists test56(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名",
tel bigint unsigned not null comment"电话号码", # 指定了非空约束,未指定唯一约束
primary key(id)
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表56";
## 查看test56表的表结构
mysql> desc test56;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | NO | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
## 往test56表中插入数据(让tel字段的数据重复,会成功,因为tel没有唯一约束)
insert into test56(name,tel) values("chenliang01",18382024221);
insert into test56(name,tel) values("chenliang02",18382024222);
insert into test56(name,tel) values("chenliang03",18382024221);
insert into test56(name,tel) values("chenliang04",18382024224);
## 查看test56表中的所有数据
mysql> select * from test56;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024221 |
| 2 | chenliang02 | 18382024222 |
| 3 | chenliang03 | 18382024221 |
| 4 | chenliang04 | 18382024224 |
+----+-------------+-------------+
4 rows in set (0.00 sec)
## 为test56表中的tel字段指定唯一约束
mysql> alter table test56 add unique uni_tel(tel);
ERROR 1062 (23000): Duplicate entry '18382024221' for key 'uni_tel'
^==提示有重复值18382024221
解决思路
## 第一阶段的思路和的操作命令:
-- 思路
A:创建一个新表(test56_new),以test56表为准(要它的索引,不要数据)
B:在新表(teset56_new)中对tel字段添加唯一约束
-- 操作的命令
use binbin;
create table if not exists test56_new like test56;
desc test56_new;
alter table test56_new add unique uni_tel(tel);
desc test56_new;
## 第二阶段的思路的操作命令
-- 思路
A:对test56表加读锁,
B:统计出表总共有少行, select count(*) from test56;
C:重复的有多少行;
B:导出test56表中的数据,并进行修改
a:insert into修改成insert ignore into
b:表名修改成test56_new
C:将B步骤处理的数据,导入到test56_new表中
-- 命令
use binbin;
lock table test56 read;
导出数据和修改,这里你不列出来了,你可以用mysqldump和sqlyog或者navicat工具
导入数据这里也不列出来了,后面看实践
## 第三阶段的思路和操作命令
-- 思路
A:对test56表进行解锁,并重命名为test56_old;
B:对test56_new表进行重命名为test56;
-- 命令
use binbin;
unlock tables;
rename table test56 to test56_old;
rename table test56_new to test56;
解决思路实践
## 第一阶段:
mysql> create table if not exists test56_new like test56;
Query OK, 0 rows affected (0.00 sec)
mysql> desc test56_new;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | NO | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> alter table test56_new add unique uni_tel(tel);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc test56_new;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | NO | UNI | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
## 第二阶段:
-- 对test56表加读锁,不让其往里面写入数据了
mysql> lock tables test56 read;
Query OK, 0 rows affected (0.00 sec)
## 第三阶段:
use binbin;
unlock tables;
rename table test56 to test56_old;
rename table test56_new to test56;
mysql> select * from test56;
+----+-------------+-------------+
| id | name | tel |
+----+-------------+-------------+
| 1 | chenliang01 | 18382024221 |
| 2 | chenliang02 | 18382024222 |
| 4 | chenliang04 | 18382024224 |
+----+-------------+-------------+
3 rows in set (0.00 sec)
mysql> desc test56;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| tel | bigint(20) unsigned | NO | UNI | NULL | |
+-------+---------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
01:主键约束实践就是主键索引,它是在表的字段级别上进行指定,一张表中只能有一个主键约束/索引
02:主键约束:包含不能重复、不能有空值,相当于unique和not null,生产中应该让其每张表都有一个主键字段,这样可以保证表中的记
录不重复,至于字段的值能不能够重复,根据你的业务需要进行相关的约束
03:主键约束:不能人为的进行命名,都是由mysql自行命名,名称为PRIMARY
04:可以是单列主键(常用),也可以是联合(多个字段)主键(不常用)
05:你用desc看到的PRI并不是你认为的primary key;有可能是表中没有primary key,但字段拥有unique和not null约束,
mysql就把它当前了主键字段
我现在有一张表,我打算让其有一个自增(auto_increment)列(id),且我想让其用为主键字段。主键约束若配合自增(auto_increment)使用时,那么主键只能在一个字段上进行创建。
## 创建test62表
create table if not exists test62(
id bigint unsigned auto_increment comment"序列", # 指定了自增
name varchar(30) not null comment"姓名",
primary key(id) # 指定了id字段为主键key
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表62";
## 查看test62表的表结构
mysql> desc test62;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
## 站在索引的角色看PRI
mysql> show index from test62 where column_name="id"\G
*************************** 1. row ***************************
Table: test62
Non_unique: 0
Key_name: PRIMARY <== key名:primary
Seq_in_index: 1
Column_name: id <== 字段名:id
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
## 站在约束的角度看PRI
mysql> select * from information_schema.table_constraints where table_schema="binbin" and table_name="test62"\G
*************************** 1. row ***************************
CONSTRAINT_CATALOG: def
CONSTRAINT_SCHEMA: binbin
CONSTRAINT_NAME: PRIMARY
TABLE_SCHEMA: binbin
TABLE_NAME: test62
CONSTRAINT_TYPE: PRIMARY KEY
1 row in set (0.00 sec)
## 往test62表中插入数据(不让id字段重复,它是自增的,就不指定它了)
mysql> insert into test62(name) values("chenliang01"),("chenliang02");
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from test62;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
+----+-------------+
2 rows in set (0.00 sec)
## 往test62表中插入数据(id字段的值每现在表中的冲突,看一看效果)
mysql> insert insert test62(id,name) values(2,"chenliang03");
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near 'insert
test62(id,name) values(2,"chenliang03")' at line 1
mysql> select * from test62;
+----+-------------+
| id | name |
+----+-------------+
| 1 | chenliang01 |
| 2 | chenliang02 |
+----+-------------+
2 rows in set (0.00 sec)
## 创建test63表
create table if not exists test63(
ip char(15) comment"IP地址",
port int unsigned comment"端口",
primary key(ip,port) # 指定了ip和port字段为主键约束
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表63";
# 其实像这种情况,我们不要用primary key,我们可以对ip和port字段用unique和not
# null来进行约束
## 查看test63表的表结构
mysql> desc test63;
+-------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| ip | char(15) | NO | PRI | NULL | |
| port | int(10) unsigned | NO | PRI | NULL | |
+-------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
# 你一个怎么有两个主键,不是说一个表只能有一个主键约束的嘛,其实它们是联合主键
## 从主键索引的角度看一年PRI
mysql> show index from test63\G
*************************** 1. row ***************************
Table: test63
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: ip
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Table: test63
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 2
Column_name: port
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
2 rows in set (0.00 sec)
## 往表中插入数据(不能重复,不能为空的哈)
mysql> insert into test63(ip,port) values
-> ("172.16.1.20",80),
-> ("172.16.1.20",81);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from test63;
+-------------+------+
| ip | port |
+-------------+------+
| 172.16.1.20 | 80 |
| 172.16.1.20 | 81 |
+-------------+------+
2 rows in set (0.00 sec)
## 往表中插入数据(我们模拟数据让其重复,肯定是要报错的)
mysql> insert into test63(ip,port) values
-> ("172.16.1.20",80),
-> ("172.16.1.30",90);
ERROR 1062 (23000): Duplicate entry '172.16.1.20-80' for key 'PRIMARY'
mysql> select * from test63;
+-------------+------+
| ip | port |
+-------------+------+
| 172.16.1.20 | 80 |
| 172.16.1.20 | 81 |
+-------------+------+
2 rows in set (0.00 sec)
我们认为的主键约束就是在字段上使用primary key关键字来进行指定。
## 创建test64表
create table if not exists test64(
id bigint unsigned auto_increment comment"序列",
name varchar(30) not null comment"姓名",
primary key(id) # 我这里指定了id字段为主键约束的哈
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表64";
## 查看test64表
mysql> desc test64;
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
+-------+---------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec) ^=不要被它骗了,它有可能不是我们认为的primary
## 从索引的角度看PRI
mysql> show index from test64\G
*************************** 1. row ***************************
Table: test64
Non_unique: 0
Key_name: PRIMARY <==看到它就可以认为是我们认为的primary key了
Seq_in_index: 1
Column_name: id <==字段名
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
## 从约束角度看一个
mysql> select * from information_schema.table_constraints where table_schema="binbin" and table_name="test64"\G
*************************** 1. row ***************************
CONSTRAINT_CATALOG: def
CONSTRAINT_SCHEMA: binbin
CONSTRAINT_NAME: PRIMARY
TABLE_SCHEMA: binbin
TABLE_NAME: test64
CONSTRAINT_TYPE: PRIMARY KEY
1 row in set (0.00 sec)
## 创建test65表
create table if not exists test65(
id bigint unsigned not null unique comment"编号", # 我指定了not null和unique
name varchar(30) not null comment"姓名"
)engine=innodb character set utf8 collate utf8_general_ci comment"测试表65";
## 查看test65表的表结构
mysql> desc test65;
+-------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+-------+
| id | bigint(20) unsigned | NO | PRI | NULL | |
| name | varchar(30) | NO | | NULL | |
+-------+---------------------+------+-----+---------+-------+
2 rows in set (0.00 sec) ^==不要认为是用primary key指定一的哈
## 从索引角度看PRI
mysql> show index from test65\G
*************************** 1. row ***************************
Table: test65
Non_unique: 0
Key_name: id <==key名不是primary就不是用primary key指定的
Seq_in_index: 1
Column_name: id <==字段名
Collation: A
Cardinality: 0
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
1 row in set (0.00 sec)
## 从约束的角度看一看PRI
mysql> select * from information_schema.table_constraints where table_schema="binbin" and table_name="test65"\G
*************************** 1. row ***************************
CONSTRAINT_CATALOG: def
CONSTRAINT_SCHEMA: binbin
CONSTRAINT_NAME: id
TABLE_SCHEMA: binbin
TABLE_NAME: test65
CONSTRAINT_TYPE: UNIQUE
1 row in set (0.00 sec)
查询某个库下哪些表有主键(PRI),不管是我们用primary key创建的,还是mysql自先的(表中没有primary key指定,但某个字段非空且唯一。
查询某个库下哪些表没有主键(PRI);
## 查询binbin库下哪些表包含主键(PRI)
select
table_schema as "库名",
table_name as "表名"
from
information_schema.tables
where
table_schema="binbin" and table_name in(
select
table_name as "表名"
from
information_schema.columns
where
table_schema="binbin" and column_key="PRI"
);
## 查询binbin库下哪些表不包含主键(PRI)
select
table_schema as "库名",
table_name as "表名"
from
information_schema.tables
where
table_schema="binbin" and table_name not in(
select
table_name as "表名"
from
information_schema.columns
where
table_schema="binbin" and column_key="PRI"
);