• MySQL之约束


    约束(CONSTRAINT)

    什么是约束?

    ​ 是一种限制,对某一个东西的限制。例如宪法规定了你违反的事情你是不能做的。这就是一种约束

    ​ 数据库的约束,是对数据的安全性,完整性的保证

    mysql中的约束有哪些?

    1. unique key(普通约束)

    唯一性约束,表示这个不能出现重复的值,

    # 完整的建表语句
    create table table_name(字段名 字段类型[长度] [约束]) charset utf8;
    
    
    # 创建表
    mysql> create table student(
        -> naem char(20) not null,
        -> gender enum("g","b") default "b",
        -> id int unique) charset utf8;
    Query OK, 0 rows affected (0.23 sec)
    
    # 查看表结构
    mysql> desc student;
    +--------+---------------+------+-----+---------+-------+
    | Field  | Type          | Null | Key | Default | Extra |
    +--------+---------------+------+-----+---------+-------+
    | naem   | char(20)      | NO   |     | NULL    |       |
    | gender | enum('g','b') | YES  |     | b       |       |
    | id     | int(11)       | YES  | UNI | NULL    |       |
    +--------+---------------+------+-----+---------+-------+
    3 rows in set (0.01 sec)
    
    
    
    mysql> insert into student values("潘立府",null,null);
    Query OK, 1 row affected (0.07 sec)
    
    mysql> select * from student;
    +-----------+--------+------+
    | naem      | gender | id   |
    +-----------+--------+------+
    | 潘立府    | NULL   | NULL |
    +-----------+--------+------+
    1 row in set (0.00 sec)
    
    # 对name字段插入null时,提示报错
    mysql> insert into student values(null,null,null);
    ERROR 1048 (23000): Column 'name' cannot be null
    
    # 对name字段给定值后,发现能够插入数据
    mysql> insert into student values("张三",null,null);
    Query OK, 1 row affected (0.06 sec)
    
    # 查看数据
    mysql> select * from student;
    +--------+--------+------+
    | name   | gender | id   |
    +--------+--------+------+
    | 张三   | NULL   | NULL |
    +--------+--------+------+
    1 row in set (0.00 sec)
    
    # 发现问题:id字段为唯一性约束,不能出现重复值,但是重复插入null值,唯一约束没有生效
    mysql> insert into student values("李四",null,null);
    Query OK, 1 row affected (0.07 sec)
    
    mysql> select * from student;
    +--------+--------+------+
    | name   | gender | id   |
    +--------+--------+------+
    | 张三   | NULL   | NULL |
    | 李四   | NULL   | NULL |
    +--------+--------+------+
    2 rows in set (0.00 sec)
    
    # 此时想把id字段的属性改为:唯一性约束 + not null ,但是发现报错,原因:表中已经存在null值。
    mysql> alter table student modify id int unique not null;
    ERROR 1062 (23000): Duplicate entry '0' for key 'id'
    
    # 于是删除数据,再修改id的属性
    mysql> delete from student;
    Query OK, 2 rows affected (0.29 sec)
    
    mysql> alter table student modify id int unique not null;
    Query OK, 0 rows affected, 1 warning (0.56 sec)
    Records: 0  Duplicates: 0  Warnings: 1
    
    mysql> desc student;
    +--------+---------------+------+-----+---------+-------+
    | Field  | Type          | Null | Key | Default | Extra |
    +--------+---------------+------+-----+---------+-------+
    | name   | char(20)      | NO   |     | NULL    |       |
    | gender | enum('g','b') | YES  |     | b       |       |
    | id     | int(11)       | NO   | PRI | NULL    |       |
    +--------+---------------+------+-----+---------+-------+
    3 rows in set (0.01 sec)
    
    
    # 此时发现,插入数据时,id不能为null了。
    mysql> insert into student values("李四",null,null);
    ERROR 1048 (23000): Column 'id' cannot be null
    

    结论:字段只设置unique唯一性约束,null值依然能够插入,原因:mysql不能对null进行比较

    2. not null

    非空约束,表示这个字段的值不能为空

    例如:账户名、密码等

    3. default

    默认值,用于给某一个字段设置默认值

    4. primary key 主键约束

    主键约束,从约束角度来看,主键等同于非空 + 唯一
    主键与普通约束的区别:

    # 创建主键字段:id
    mysql> create table persong(
        -> id char(19) primary key,
        -> name char(20));
    Query OK, 0 rows affected (0.46 sec)
    
    # OK
    mysql> insert into persong values("1","rose");
    Query OK, 1 row affected (0.29 sec)
    
    # 主键冲突
    mysql> insert into persong values("1","rose");
    ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
    
    mysql> desc persong;
    +-------+----------+------+-----+---------+-------+
    | Field | Type     | Null | Key | Default | Extra |
    +-------+----------+------+-----+---------+-------+
    | id    | char(19) | NO   | PRI | NULL    |       |
    | name  | char(20) | YES  |     | NULL    |       |
    +-------+----------+------+-----+---------+-------+
    2 rows in set (0.01 sec)
    

    主键的特点:

    1. 主键是一种索引,索引的作用是加速查询效率。因此主键约束能加速我们查询的效率。

      在执行sql语句的前面加上:explain 可查看sql语句的执行计划

    2. 主键对于innodb引擎来说是必须要的,没有不行。即使我们在创建innodb引擎的表,没有创建主键,系统也会自动创建一个隐藏的主键。

    3. 一个表中只能存在一个主键


    auto_increment(自增长)

    mysql> create table teacher (id int primary key auto_increment,name char(20));
    Query OK, 0 rows affected (0.47 sec)
    
    # 第一种插入方法
    mysql> insert into teacher values(null,"jack");
    Query OK, 1 row affected (0.28 sec)
    
    mysql> insert into teacher values(null,"rose");
    Query OK, 1 row affected (0.29 sec)
    
    mysql> insert into teacher values(null,"panlifu");
    Query OK, 1 row affected (0.29 sec)
    
    mysql> insert into teacher values(null,"lt");
    Query OK, 1 row affected (0.06 sec)
    
    mysql> select * from teacher;
    +----+---------+
    | id | name    |
    +----+---------+
    |  1 | jack    |
    |  2 | rose    |
    |  3 | panlifu |
    |  4 | lt      |
    +----+---------+
    4 rows in set (0.00 sec)
    
    # 第二种方式 插入数据
    mysql> insert into teacher(name) values("xs");
    Query OK, 1 row affected (0.29 sec)
    
    mysql> select * from teacher;
    +----+---------+
    | id | name    |
    +----+---------+
    |  1 | jack    |
    |  2 | rose    |
    |  3 | panlifu |
    |  4 | lt      |
    |  5 | xs      |
    +----+---------+
    5 rows in set (0.00 sec)
    
    # 当auto_increment 约束 primary key时,即使我们插入数据指定为自增列为空,系统也会帮助我们自动增长。
    

    5. foreign key 外键约束

    一. 数据出现了大量的重复

    二. 数据结构环混乱(耦合度高)

    三. 当后期修改数据时,由于有大量的重复数据,必须每个都修改

    如何创建外键索引:

    第一阶段
    1. 应该先确定主键所在表的数据结构。例如:部门表(主表)

      create table dept(
      	id int primary key auto_increment,
          name char(20),
          job char(50),
          manager char(30)
      ) charset utf8;
      
      1. 在确认外键所在表的数据结构。例如:员工表(从表、子表)
    create table teacher(
       	id int primary key auto_increment,
           name char(20),
           gender char(21),
           dept_id int
       ) charset utf8;
    

    这里存在缺点:部门表和员工表之间没有建立联系,目前部门表修改数据,员工表无感知


    第二阶段
    1. 对员工表进行约束(跟部门表建立联系)
    create table teacher(
       	id int primary key auto_increment,
           name char(20),
           gender char(21),
           dept_id int,
           foreign key(dept_id) references dept(id)
       ) charset utf8;
       
       # dept_id 表示员工表的外键字段
       # dept 表示要关联的哪个表,这里指部门表
       # references  引用的意思
       # dept(id)  表示要关联dept表中的id字段
    

    这样从表就跟主表建立了外键联系。


    第三阶段:建立级联操作

    因为外键存在第4点和第5点的原因,因此才有了级联的操作,来简化对数据库的管理

    另外级联是建立在子表中的。

    # 主库
    create table dept(
    	id int primary key auto_increment,
     name char(20),
     job char(50),
        manager char(30)
       ) charset utf8;
       
    
    # 子表
    create table teacher(
    	id int primary key auto_increment,
     name char(20),
     gender char(21),
        dept_id int,
        foreign key(dept_id) references dept(id)
        on update cascade
        on delete cascade
       ) charset utf8;
       
    # one delete cascade   应对 特征中的第4点
    # on update cascade    应对 特征中的第5点
    

    总结特征:

    1. 外键字段的数据类型必须跟关联表的字段类型 相近或者相等。例如主键的数据类型为int,外键的数据类型可以为logint等其他的整型数据。但是不能为字符串,date等数据

    2. 在从表中插入数据时,如果主表不存在对应的数据,那么会导致插入失败。

       create table dept(
       	id int primary key auto_increment,
           name char(20),
           job char(50),
           manager char(30)
       ) charset utf8;
       
       create table teacher(
       	id int primary key auto_increment,
           name char(20),
           gender char(21),
           dept_id int,
           foreign key(dept_id) references dept(id)
       ) charset utf8;
       
       mysql> insert into teacher values(null,"bgon","m",1);
       ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`plf`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`))
       
    
    1. 从表更新外键时,必须保证外键的值在主表中是存在的
       create table dept(
       	id int primary key auto_increment,
           name char(20),
           job char(50),
           manager char(30)
       ) charset utf8;
       
       create table teacher(
       	id int primary key auto_increment,
           name char(20),
           gender char(21),
           dept_id int,
           foreign key(dept_id) references dept(id)
       ) charset utf8;
       
       mysql> select *from dept;
       Empty set (0.00 sec)
       
       mysql> select * from teacher;
       Empty set (0.00 sec)
       
       mysql> insert into dept values(null,"教学部","教学","bgon");
       Query OK, 1 row affected (0.29 sec)
       
       mysql> insert into dept values(null,"销售部","销售","plf");
       Query OK, 1 row affected (0.07 sec)
       
       mysql> select *from dept;
       +----+-----------+--------+---------+
       | id | name      | job    | manager |
       +----+-----------+--------+---------+
       |  1 | 教学部    | 教学   | bgon    |
       |  2 | 销售部    | 销售   | plf     |
       +----+-----------+--------+---------+
       2 rows in set (0.00 sec)
       
       mysql> insert into teacher values(null,'张三',"男",1);
       Query OK, 1 row affected (0.30 sec)
       
       mysql> select *from teacher;
       +----+--------+--------+---------+
       | id | name   | gender | dept_id |
       +----+--------+--------+---------+
       |  1 | 张三   | 男     |       1 |
       +----+--------+--------+---------+
       1 row in set (0.00 sec)
       
       # 当将dept_id更新为3时,报错。原因:主表中并没有编号为3的数据
       mysql> update teacher set dept_id = 3 where id =1;
       ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`))
       mysql>
    
    1. 删除主表记录前,要保证从表中没有外键关联被删除的id(可以级联)
       mysql> select *from dept;
       +----+-----------+--------+---------+
       | id | name      | job    | manager |
       +----+-----------+--------+---------+
       |  1 | 教学部    | 教学   | bgon    |
       |  2 | 销售部    | 销售   | plf     |
       +----+-----------+--------+---------+
       2 rows in set (0.00 sec)
       
       mysql> select *from teacher;
       +----+--------+--------+---------+
       | id | name   | gender | dept_id |
       +----+--------+--------+---------+
       |  1 | 张三   | 男     |       1 |
       +----+--------+--------+---------+
       1 row in set (0.00 sec)
       
       mysql> delete from dept where id = 1;
       ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`))
    
    1. 更新主表记录的主键时,要保证从表中没有外键关联被删除的id(可以级联)
       mysql> select *from dept;
       +----+-----------+--------+---------+
       | id | name      | job    | manager |
       +----+-----------+--------+---------+
       |  1 | 教学部    | 教学   | bgon    |
       |  2 | 销售部    | 销售   | plf     |
       +----+-----------+--------+---------+
       2 rows in set (0.00 sec)
       
       mysql> select *from teacher;
       +----+--------+--------+---------+
       | id | name   | gender | dept_id |
       +----+--------+--------+---------+
       |  1 | 张三   | 男     |       1 |
       +----+--------+--------+---------+
       1 row in set (0.00 sec)
       
       # 当更新主表编号为1的部门时,因为编号1部门下有一个人,所以不能更新
       mysql> update dept set id = 3 where id=1;
       ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test`.`teacher`, CONSTRAINT `teacher_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `dept` (`id`))
       mysql>
    
    1. 必须先创建主表,子表才能用外键
       
    
    1. 删除表的操作,先删除从表,再删除主表
       mysql> select *from dept;
       +----+-----------+--------+---------+
       | id | name      | job    | manager |
       +----+-----------+--------+---------+
       |  1 | 教学部    | 教学   | bgon    |
       |  2 | 销售部    | 销售   | plf     |
       +----+-----------+--------+---------+
       2 rows in set (0.00 sec)
       
       mysql> select *from teacher;
       +----+--------+--------+---------+
       | id | name   | gender | dept_id |
       +----+--------+--------+---------+
       |  1 | 张三   | 男     |       1 |
       +----+--------+--------+---------+
       1 row in set (0.00 sec)
       
       # 不能删除
       mysql> drop table dept;
       ERROR 1217 (23000): Cannot delete or update a parent row: a foreign key constraint fails
    

    级联操作

    产生的原因:

    当我们需要删除部门(主表)信息时,必须先删除从表中关联的数据,很麻烦。

    级联操作指的就是,当你操作主表时,自动操作从表

    两种级联的定义方式

    一. 在表定义阶段进行定义:
    1. 级联的删除

      create table student_b(
      	class_id int,
          name char(10),
          age int,
          foreign key(class_id) references class_b(id)
          on delete cascade
      ) charset utf8;
      
    2. 级联的更新

      create table student_b(
      	class_id int,
       name char(10),
          age int,
          foreign key(class_id) references class_b(id)
          on update cascade
      ) charset utf8;
      
    3. 级联的删除和更新

      create table teacher(
      	id int primary key auto_increment,
      	name char(20),
      	gender char(21),
       	dept_id int,
       	foreign key(dept_id) references dept(id)
       	on update cascade
       	on delete cascade
      ) charset utf8;
      
    二. 表存在的情况下,先将之前的外键删除掉,然后通过alter增加外键级联:
    # 删除外键
    mysql> alter table teacher drop foreign key 外键的ID;
    
    # 增加外键并增加级联删除和更新
    mysql> alter table teacher add constraint dept_id foreign key(dept_id) references dept(id) on delete cascade on update cascade;
    
  • 相关阅读:
    discuz X3.2 自定义系统广告详解
    windows平台myeclipse+PDT+apache+xdebug调试php
    南浮的IT民工
    linux实践——编译安装两个apache
    如何使maven+jetty运行时不锁定js和css[转]
    linux实践——ubuntu搭建 svn 服务
    测试代码插件(插入代码块)
    FTP 文件接口按天批处理脚本实例
    7月份工作小结
    报表开发过程
  • 原文地址:https://www.cnblogs.com/plf-Jack/p/11177019.html
Copyright © 2020-2023  润新知