真正 约束 字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是email,要求是唯一的。
在MySQL中,约束(Constraints) 是指在创建表时规定的对表中的数据进行限制的条件。它可以对表中某列或某几列添加一些限制条件,以保证表中的数据符合要求,MySQL中的约束包括以下几种:
- 主键约束(Primary Key Constraint):用于标识表中每条记录的唯一性,每张表只能有一个主键,主键值不能重复且不能为空。
- 唯一约束(Unique Constraint):用于保证某个列的数据唯一性,每个表可以有多个唯一约束。
- 非空约束(Not Null Constraint):用于保证某个列的值不能为空,一个表中可以有多个非空约束。
- 外键约束(Foreign Key Constraint):用于关联两个表的数据,确保两个表之间的关联关系是有效的。外键约束必须在关联表的列上定义,他会限制在被关联的表中不能存在没有对应主键或唯一键值的记录。
MySQL中的 空属性 指的是一个字段没有值的情况,可以使用null关键字来表示。null是一个特殊的值,表示一个未知的、不存在的或不适用的值。与之相对的是空字符串(' '), 它表示一个空的字符串值,不同于null。在MySQL中,可以在列定义时指定该列是否允许为空。如果列允许为空,则该列可以包含null值。否则,该列必须包含非null值。
空属性在数据库中很常见,比如一个订单表中,如果订单尚未付款,则该订单的付款时间段可能为空。在查询时,可以使用is null 或 is not null 运算符来判断某个字段是否为空。
数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据库为空没办法参与运算。
示例:
创建一个班级表,包含班级名称和班级所在的教室。站在正常的业务逻辑中:
所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中,这就是约束。
mysql> create table if not exists myclass( -> class_name varchar(20) not null, -> class_room varchar(20) not null, -> other varchar(20) -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc myclass; +------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+-------+ | class_name | varchar(20) | NO | | NULL | | | class_room | varchar(20) | NO | | NULL | | | other | varchar(20) | YES | | NULL | | +------------+-------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> insert into myclass (class_name, class_room, other) values ('高三二班','101教师', '普通班'); Query OK, 1 row affected (0.01 sec) mysql> insert into myclass (class_name, class_room) values ('高三三班','1003教师'); Query OK, 1 row affected (0.00 sec) mysql> select * from myclass; +--------------+------------+-----------+ | class_name | class_room | other | +--------------+------------+-----------+ | 高三二班 | 101教师 | 普通班 | | 高三三班 | 1003教师 | NULL | +--------------+------------+-----------+ mysql> insert into myclass (class_name) values ('高三5班'); ERROR 1364 (HY000): Field 'class_room' doesn't have a default value mysql> insert into myclass (class_name, class_room) values ('高三5班', NULL); ERROR 1048 (23000): Column 'class_room' cannot be null mysql> insert into myclass (class_name, class_room) values (NULL, NULL); ERROR 1048 (23000): Column 'class_name' cannot be null
这里我们可以看到班级名和班级教室不能为空。
同理,当我们插入空值时就会报错。
在MySQL中,可以为表的列指定默认值,当插入数据时,如果未显示指定该列的值,则会自动填充该列的值为默认值。这样可以方便地为表中地某些列设置默认值,避免重复性工作。
默认值可以是一个常量值,也可以是一个函数表达式,比如 CURRENT_TIMESTAMP 表示当前地时间戳。当使用函数表达式时,每次插入数据时该表达式都会被重新计算并填充为该列地默认值。
在创建表时可以通过 default 关键字来指定列地默认值。
mysql> create table if not exists t2( -> name varchar(20) not null, -> age tinyint unsigned default 18, -> gender char(2) default '男' -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc t2; +--------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+---------------------+------+-----+---------+-------+ | name | varchar(20) | NO | | NULL | | | age | tinyint(3) unsigned | YES | | 18 | | | gender | char(2) | YES | | 男 | | +--------+---------------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> insert into t2 (name) values ('张三'); Query OK, 1 row affected (0.01 sec) mysql> insert into t2 (name,age) values ('李四',25); Query OK, 1 row affected (0.00 sec) mysql> insert into t2 (name,gender) values ('王五','女'); Query OK, 1 row affected (0.01 sec) mysql> select * from t2; +--------+------+--------+ | name | age | gender | +--------+------+--------+ | 张三 | 18 | 男 | | 李四 | 25 | 男 | | 王五 | 18 | 女 | +--------+------+--------+ 3 rows in set (0.00 sec)
这里我们在创建表时,指定了姓名不能为空,年龄默认为18岁,性别为默认值。因此我们在插入’李四’时,未指定性别、默认为男;在插入’王五’时,未指定年龄,默认为18岁。
not null 和 default 结合
列描述(comment) 是一个可选的属性,可以用来描述表中每个列的含义、作用、限制等信息。它通常在创建表时定义,并可以通过 show create table 语句查看。列描述不会影响数据库的结构和功能,它只是一个用于更好的理解和维护表结构的工具。
列描述通常用于以下目的:
mysql> create table if not exists t3( -> name varchar(20) not null, -> age tinyint default 18 comment '禁止18岁以下的用户注册', -> gender char(1) not null default '男' comment '用户的性别' -> ); Query OK, 0 rows affected (0.02 sec) mysql> show create table t3\G *************************** 1. row *************************** Table: t3 Create Table: CREATE TABLE `t3` ( `name` varchar(20) NOT NULL, `age` tinyint(4) DEFAULT '18' COMMENT '禁止18岁以下的用户注册', `gender` char(1) NOT NULL DEFAULT '男' COMMENT '用户的性别' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> insert into t3 (name,age,gender) values('猪八戒', 19, '男'); Query OK, 1 row affected (0.01 sec) mysql> insert into t3 (name,age) values('猪八戒', null); Query OK, 1 row affected (0.00 sec) mysql> select * from t3; +-----------+------+--------+ | name | age | gender | +-----------+------+--------+ | 猪八戒 | 19 | 男 | | 猪八戒 | NULL | 男 | +-----------+------+--------+ 2 rows in set (0.00 sec)
列描述说明了每个列的含义和作用,以及表的含义。这可以帮助开发人员更好地理解表的结构,规范数据的输入,并且方便维护人员进行版本管理和回溯。
通常情况下,MySQL会省略数值类型数据类型中的前导零。zerofill 是一种列属性,用于将数字类型的列填充为固定长度,填充的内容为0。在使用zerofill属性时,如果插入的数据长度小于指定长度。这个属性通常用于需要固定长度列,比如身份证号码等。需要注意的是,zerofill只对数值类型的数据类型有效,对于其他类型的列属性,无法设置zerofill约束。
int(len) 中的len表示整数类型字段的显示宽度,即在输出时该字段最多显示的字符数,它只是为了控制该字段在输出时的显示效果,而不会影响该字段在存储时的大小和范围。如果超过了定义的显示宽度,则将该数字进行原样显示。int(len)需要设置了zerofill属性,才会起作用。注:10位能够覆盖unsigned int的全部数据,而 int 比 unsigned int 多一位符号位。
mysql> create table if not exists t4( -> num1 int, -> num2 int(5) unsigned zerofill -> ); Query OK, 0 rows affected (0.01 sec) mysql> insert into t4 values(10,20); Query OK, 1 row affected (0.00 sec)
mysql> insert into t4 values(12345, 54321); Query OK, 1 row affected (0.00 sec)
使用zerofill 属性的主要优点是可以确保数据以相同的格式存储,这在某些情况下可以提高查询和排序的性能。此外,它还可以是数据更易于阅读和比较。
主键(Primary Key):用于唯一标识表中每一条记录,确保记录的唯一性和完整性。主键列不允许重复,不允许为空。一个表中最多只能有一个主键,主键的所在列通常是整数类型。
mysql> create table if not exists t5( -> id int unsigned primary key comment '学生的学号是主键', -> name varchar(20) not null -> ); Query OK, 0 rows affected (0.02 sec)
💕 追加主键
alter table 表名 add primary key(字段列表);
💕 删除主键
alter table 表名 drop primary key;
💕 复合主键
复合主键是指在一个表中,主键由多个列组成而不是单独的一列。这样的设计可以更准确地表示实际数据地唯一性,因为在复杂地应用场景中,单独的一列很可能不能完全确定唯一性。
注意,复合主键不同于单一地主键,其顺序是有意义的。因此需要根据实际情况来确定复合主键的顺序,以确保能够把正确地反映数据的唯一性。
mysql> create table if not exists t6( -> id varchar(20) comment '学号', -> course varchar(30) comment '课程编号', -> score tinyint unsigned default 60 comment '成绩', -> primary key(id, course) -> ); Query OK, 0 rows affected (0.01 sec) mysql> desc t6; +--------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+---------------------+------+-----+---------+-------+ | id | varchar(20) | NO | PRI | NULL | | | course | varchar(30) | NO | PRI | NULL | | | score | tinyint(3) unsigned | YES | | 60 | | +--------+---------------------+------+-----+---------+-------+ 3 rows in set (0.00 sec) mysql> show create table t6\G *************************** 1. row *************************** Table: t6 Create Table: CREATE TABLE `t6` ( `id` varchar(20) NOT NULL COMMENT '学号', `course` varchar(30) NOT NULL COMMENT '课程编号', `score` tinyint(3) unsigned DEFAULT '60' COMMENT '成绩', PRIMARY KEY (`id`,`course`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
💕 设计主键的原则:
设计主键时需要根据具体的业务需求来确定,一般情况下可以选择使用自增长 ID 作为主键,也可以选择一个稳定、唯一、简洁的自然键作为主键。
自增长(Auto Increment) 是MySQL中一种常见的特殊类型的列属性,用于再插入数据时自动分配递增的值。一般来说,自增长属性适用于那些需要每次插入一条新纪录时,自动生成一个唯一的、递增的编号的表中的列。自增长通常和主键搭配使用,作为逻辑主键。
自增长的特点:
mysql> create table if not exists t7( -> id int unsigned primary key auto_increment, -> name varchar(20) not null -> );
当我们显示插入id值时,会影响到 auto_increment,auto_increment 等于这列的最大值+1,为下一次插入的自增值。
💕 指定自增起始值
alter table table_name auto_increment = 起始值;
💕 设置自增步长
# mysql自增的步长 show session variables like 'auto_inc%'; # 基于会话级别 set session auto_increment_increment=2 # 修改会话级别的步长 # 基于全局级别的 set global auto_increment_increment=2 # 修改全局级别的步长(所有会话都生效)
在关系型数据库中,索引 是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单,可以提高对数据库表中数据的访问速度。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
索引提供指向存储在表的指定列中的数据值的指针,然后根据您指定的排序顺序对这些指针排序。数据库使用索引以找到特定值,然后顺指针找到包含该值的行。这样可以使对应于表的SQL语句执行得更快,可以快速访问数据库表中得特定信息。
虽然索引可以提高查询性能,但是在设计索引时也需要注意,过多或不必要的索引会影响数据更新的性能,增加数据存储空间,并且索引的设计需要结合具体业务场景和查询需求。
唯一键(Unique Key) 是一种约束,它用于保证某个列的数据唯一性,每个表可以有多个唯一约束。与主键不同的是,唯一键允许空值,即可以在列中包含空值,但不能有重复值。
在现实生活中,我们身上有非常多具有唯一性的值,如身份证号、QQ号等。一般而言,主键只是众多具有唯一性的属性列中的一列,该列被选择成为主键。但这并不意味着其他具有唯一性的列不需要保证唯一性。但是主键只能有一个,所以MySQL就提供了另一个保证列信息唯一性的方法:唯一键。唯一键和主键并不冲突,两者时互相补充的,共同维护表的完整性!!!
举个栗子:
假设一个场景(当然,具体可能并不是这样,仅仅为了帮助大家理解) 比如在公司,我们需要一个员工管理系统,系统中有一个员工表,员工表中有两列信息,一个身份证号码,一个是员工工号,我们可以选择身份号码作为主键。 而我们设计员工工号的时候,需要一种约束:而所有的员工工号都不能重复。 具体指的是在公司的业务上不能重复,我们设计表的时候,需要这个约束,那么就可以将员工工号设计成为唯一键。 一般而言,我们建议将主键设计成为和当前业务无关的字段,这样,当业务调整的时候,我们可以尽量不会对主键做过大的调整。
mysql> create table if not exists students( id int unsigned primary key auto_increment, name varchar(20) not null, qq varchar(30) unique comment 'QQ号需要保证唯一性')auto_increment=1000; Query OK, 0 rows affected (0.01 sec) mysql> insert into students(name,qq) values('张三',10001); Query OK, 1 row affected (0.01 sec) mysql> insert into students(name,qq) values('李四',10001); ERROR 1062 (23000): Duplicate entry '10001' for key 'qq' mysql> insert into students(name,qq) values('李四',10002); Query OK, 1 row affected (0.00 sec) mysql> select * from students; +------+--------+-------+ | id | name | qq | +------+--------+-------+ | 1000 | 张三 | 10001 | | 1002 | 李四 | 10002 | +------+--------+-------+ 2 rows in set (0.00 sec)
这里我们可以看到,当我们插入(‘李四’, 10001)时,产生了唯一键冲突。
如果给唯一键加上 not null 约束,那么这个唯一键和主键就非常相似了。不过两者还有一些差别,在索引部分将进行详解。
比如先创建一个班级表作为主表,表当中包含班级的id和班级名,并将班级id设置为主键。如下:
mysql> create table class_table( -> class_id int unsigned primary key comment '班级id', -> name varchar(20) not null comment '班级名' -> ); Query OK, 0 rows affected (0.02 sec)
再创建一个学生表作为从表,表当中包含学生的id、姓名以及学生所在班级对应的id,并将学生表中的班级id列设置成外键,关联到班级表中的班级id列。如下:
mysql> create table student_table( -> stu_id int unsigned primary key comment '学生id', -> name varchar(20) not null comment '学生姓名', -> class_id int unsigned comment '学生所在的班级对应的id', -> foreign key(class_id) references class_table(class_id) -> ); Query OK, 0 rows affected (0.01 sec)
表创建完毕后查看学生表的表结构,可以看到学生表中的班级id对应的Key列出现了MUL标志,这表明class_id已经被成功设置成了外键。如下:
为了演示外键约束,我们先向班级表中插入两条记录。如下:
此时向学生表中插入记录,如果插入的记录对应的班级id是班级表中存在的,或者插入的班级id为null,那么此时是允许进行插入的。如下:
这里我们可以看到,当插入学生表的这条记录所对应的班级并不存在时,此时将会插入失败,这就是外键约束。
说明一下:
案例描述
有一个商店的数据,记录客户及购物情况,有以下三个表组成:
provider
要求:
SQL编写
首先我们需要创建一个数据库,然后在该数据库中完成这三张表的创建。如下:
mysql> create database store_data; Query OK, 1 row affected (0.00 sec) mysql> use store_data; Database changed
创建商品表时,将商品编号设置成主键并且可以将其设置成自增长字段,其他字段的属性没有要求可以自行合理设置。如下:
mysql> create table goods( -> goods_id int primary key auto_increment comment '商品编号', -> goods_name varchar(32) not null comment '商品名称', -> unitprice int not null default 0 comment '单价(分)', -> category varchar(64) not null comment '供应商' -> ); Query OK, 0 rows affected (0.02 sec) mysql> desc goods; +------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+----------------+ | goods_id | int(11) | NO | PRI | NULL | auto_increment | | goods_name | varchar(32) | NO | | NULL | | | unitprice | int(11) | NO | | 0 | | | category | varchar(64) | NO | | NULL | | +------------+-------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec)
创建客户表时,将客户编号设置成主键并且可以将其设置成自增长字段,然后给姓名设置 not null 属性,将邮箱设置成唯一键,将邮箱设置成唯一键,将性别设置成enum类型并仅提供男女性别选项,此外,题目虽然没有对身份证做要求,但正常来说身份证也应该保持唯一性,最好设置成唯一键。如下:
mysql> create table customer( -> customer_id int primary key auto_increment comment '客户编号', -> name varchar(32) not null comment '客户姓名', -> address varchar(256) not null comment '客户住址', -> email varchar(64) unique comment '客户邮箱', -> sex enum('男','女') not null comment '客户性别', -> card_id char(18) unique comment '客户身份证' -> ); Query OK, 0 rows affected (0.02 sec) mysql> desc customer; +-------------+-------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+-------------------+------+-----+---------+----------------+ | customer_id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(32) | NO | | NULL | | | address | varchar(256) | NO | | NULL | | | email | varchar(64) | YES | UNI | NULL | | | sex | enum('男','女') | NO | | NULL | | | card_id | char(18) | YES | UNI | NULL | | +-------------+-------------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec)
创建购买表时,将订单号设置成主键并且可以将其设置成自增长字段,然后将客户编号和商品编号设置成外键,分别关联到客户表和商品表中的客户编号和商品编号,用外键约束来保证每一个订单的客户编号和商品编号都是存在的。如下:
mysql> create table purchase( -> order_id int primary key auto_increment comment '订单号', -> customer_id int comment '客户编号', -> goods_id int comment '商品编号', -> nums int default 1 comment '购买数量', -> foreign key(customer_id) references customer(customer_id), -> foreign key(goods_id) references goods(goods_id) -> ); Query OK, 0 rows affected (0.02 sec) mysql> desc purchase; +-------------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------+------+-----+---------+----------------+ | order_id | int(11) | NO | PRI | NULL | auto_increment | | customer_id | int(11) | YES | MUL | NULL | | | goods_id | int(11) | YES | MUL | NULL | | | nums | int(11) | YES | | 1 | | +-------------+---------+------+-----+---------+----------------+ 4 rows in set (0.00 sec)
上一篇:Python类的继承