• 数据库——MySQL——完整性约束


     约束,就是用来保证数据完整性和一致性的。

    常见的约束分为:

    PRIMARY KEY (PK)    标识该字段为该表的主键,可以唯一的标识记录
    FOREIGN KEY (FK)    标识该字段为该表的外键
    NOT NULL    标识该字段不能为空
    UNIQUE KEY (UK)    标识该字段的值是唯一的
    AUTO_INCREMENT    标识该字段的值自动增长(整数类型,而且为主键)
    DEFAULT    为该字段设置默认值
    
    UNSIGNED 无符号
    ZEROFILL 使用0填充

    下面会说其中的一部分

    unique 唯一索引

    使用方式

    ============设置唯一约束 UNIQUE===============
    方法一:
    create table department1(
    id int,
    name varchar(20) unique,
    comment varchar(100)
    );
    
    
    方法二:
    create table department2(
    id int,
    name varchar(20),
    comment varchar(100),
    constraint uk_name unique(name)
    );
    
    
    mysql> insert into department1 values(1,'IT','技术');
    Query OK, 1 row affected (0.00 sec)
    mysql> insert into department1 values(1,'IT','技术');
    ERROR 1062 (23000): Duplicate entry 'IT' for key 'name'

    如果是not null和unique进行组合的话,会变成主键

    mysql> create table t1(id int not null unique);
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> desc t1;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | id    | int(11) | NO   | PRI | NULL    |       |
    +-------+---------+------+-----+---------+-------+
    row in set (0.00 sec)
    create table service(
    id int primary key auto_increment,
    name varchar(20),
    host varchar(15) not null,
    port int not null,
    unique(host,port) #联合唯一
    );
    
    mysql> insert into service values
        -> (1,'nginx','192.168.0.10',80),
        -> (2,'haproxy','192.168.0.20',80),
        -> (3,'mysql','192.168.0.30',3306)
        -> ;
    Query OK, 3 rows affected (0.01 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    mysql> insert into service(name,host,port) values('nginx','192.168.0.10',80);
    ERROR 1062 (23000): Duplicate entry '192.168.0.10-80' for key 'host'
    
    联合唯一
    联合唯一

    primary key主键

    从约束角度看primary key字段的值不为空且唯一,那我们直接使用not null+unique不就可以了吗,要它干什么?

    innodb称之为索引组织表,一张表中必须有且只有一个主键。主键primary key是innodb存储引擎组织数据的依据。

    一个表中可以有两种形式:

    • 单列做主键
    • 多列做主键(复合主键)
    ============单列做主键===============
    #方法一:not null+unique
    create table department1(
    id int not null unique, #主键
    name varchar(20) not null unique,
    comment varchar(100)
    );
    
    mysql> desc department1;
    +---------+--------------+------+-----+---------+-------+
    | Field   | Type         | Null | Key | Default | Extra |
    +---------+--------------+------+-----+---------+-------+
    | id      | int(11)      | NO   | PRI | NULL    |       |
    | name    | varchar(20)  | NO   | UNI | NULL    |       |
    | comment | varchar(100) | YES  |     | NULL    |       |
    +---------+--------------+------+-----+---------+-------+
    rows in set (0.01 sec)
    
    #方法二:在某一个字段后用primary key
    create table department2(
    id int primary key, #主键
    name varchar(20),
    comment varchar(100)
    );
    
    mysql> desc department2;
    +---------+--------------+------+-----+---------+-------+
    | Field   | Type         | Null | Key | Default | Extra |
    +---------+--------------+------+-----+---------+-------+
    | id      | int(11)      | NO   | PRI | NULL    |       |
    | name    | varchar(20)  | YES  |     | NULL    |       |
    | comment | varchar(100) | YES  |     | NULL    |       |
    +---------+--------------+------+-----+---------+-------+
    rows in set (0.00 sec)
    
    #方法三:在所有字段后单独定义primary key
    create table department3(
    id int,
    name varchar(20),
    comment varchar(100),
    constraint pk_name primary key(id); #创建主键并为其命名pk_name
    
    mysql> desc department3;
    +---------+--------------+------+-----+---------+-------+
    | Field   | Type         | Null | Key | Default | Extra |
    +---------+--------------+------+-----+---------+-------+
    | id      | int(11)      | NO   | PRI | NULL    |       |
    | name    | varchar(20)  | YES  |     | NULL    |       |
    | comment | varchar(100) | YES  |     | NULL    |       |
    +---------+--------------+------+-----+---------+-------+
    rows in set (0.01 sec)
    单列主键
    ==================多列做主键================
    create table service(
    ip varchar(15),
    port char(5),
    service_name varchar(10) not null,
    primary key(ip,port)
    );
    
    
    mysql> desc service;
    +--------------+-------------+------+-----+---------+-------+
    | Field        | Type        | Null | Key | Default | Extra |
    +--------------+-------------+------+-----+---------+-------+
    | ip           | varchar(15) | NO   | PRI | NULL    |       |
    | port         | char(5)     | NO   | PRI | NULL    |       |
    | service_name | varchar(10) | NO   |     | NULL    |       |
    +--------------+-------------+------+-----+---------+-------+
    rows in set (0.00 sec)
    
    mysql> insert into service values
        -> ('172.16.45.10','3306','mysqld'),
        -> ('172.16.45.11','3306','mariadb')
        -> ;
    Query OK, 2 rows affected (0.00 sec)
    Records: 2  Duplicates: 0  Warnings: 0
    
    mysql> insert into service values ('172.16.45.10','3306','nginx');
    ERROR 1062 (23000): Duplicate entry '172.16.45.10-3306' for key 'PRIMARY'
    
    多列主键
    多列主键

    auto_increment自增

    这里对使用自增做几点说明

    • 给字段设置自增之后,还是可以给该字段赋值的
    • 如果用delete删除了记录后,再插入值,该字段仍按照删除前的位置继续增长
    • truncate是清空表,而delete是一条条的删记录,当用truncate清空表中之后,设置的自增的字段重新从1开始自增。
    # auto_increment_increment这是自增长的步长。
    # auto_increment_offset这是自增长开始的值
    
    #基于会话级别
    #比如:set session auth_increment_increment=2 #修改会话级别的步长
    
    #基于全局级别的
    #比如:set global auth_increment_increment=2 #修改全局级别的步长(所有会话都生效)
    
    
    mysql> set global auto_increment_increment=5;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> set global auto_increment_offset=3;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> show variables like 'auto_incre%'; #需要退出重新登录
    +--------------------------+-------+
    | Variable_name            | Value |
    +--------------------------+-------+
    | auto_increment_increment | 1     |
    | auto_increment_offset    | 1     |
    +--------------------------+-------+
    例子

    foreign key 外键

    为什么会产生外键,举个例子:

    员工信息表有三个字段:工号  姓名  部门

    公司有3个部门,但是有1个亿的员工,那意味着部门这个字段需要重复存储,部门名字越长,越浪费

    解决方法:

    我们完全可以定义一个部门表

    然后让员工信息表关联该表,如何关联,即foreign key

    使用外键要注意的:

    • 表的类型必须是innodb存储引擎
    • 被关联的字段,也就是另一个表中的字段,必须保证唯一。

    外键的定义语法:

    [CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
        REFERENCES tbl_name (index_col_name, ...)
        [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]
        [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT}]

     说明:

    该语法可以在 CREATE TABLE 和 ALTER TABLE 时使用,

    CONSTRAINT symbol,是给这个约束增加一个名字,如果不指定MYSQL会自动生成一个名字。
    ON DELETE、ON UPDATE表示事件触发限制,可设参数:
    RESTRICT(限制外表中的外键改动)
    CASCADE(跟随外键改动)
    SET NULL(设空值)
    SET DEFAULT(设默认值)
    NO ACTION(无动作,默认的)

    例子:

    说明,这个例子是在网上看到的,虽然有些说明不好,但比较有条理而且易于理解的,原文地址为:http://www.cppblog.com/wolf/articles/69089.html

    # 创建两张表,一个是大哥表,一个小弟表,大哥表的id是小弟表的外键。
    CREATE TABLE `dage` (
      `id` int(11) NOT NULL auto_increment,
      `name` varchar(32) default '',
      PRIMARY KEY  (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    CREATE TABLE `xiaodi` (
      `id` int(11) NOT NULL auto_increment,
      `dage_id` int(11) default NULL,
      `name` varchar(32) default '',
      PRIMARY KEY  (`id`),
      KEY `dage_id` (`dage_id`),
      CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    
    # 大哥表中插入一个记录
    mysql> insert into dage(name) values('铜锣湾');
    Query OK, 1 row affected (0.01 sec)
    mysql> select * from dage;
    +----+--------+
    | id | name   |
    +----+--------+
    |  1 | 铜锣湾 |
    +----+--------+
    1 row in set (0.00 sec)
    
    # 小弟表中插入一个记录
    mysql> insert into xiaodi(dage_id,name) values(1,'铜锣湾_小弟A');
    Query OK, 1 row affected (0.02 sec)
    
    mysql> select * from xiaodi;
    +----+---------+--------------+
    | id | dage_id | name         |
    +----+---------+--------------+
    |  1 |       1 | 铜锣湾_小弟A |
    +----+---------+--------------+
    
    # 想要删除大哥中的一个记录,这个时候会提示,这个大哥是一个小弟的外键,不让删
    mysql> delete from dage where id=1;
    ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`bstar/xiaodi`, CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`))
    
    # 这个时候给大哥的外键约束增加时间触发限制
    
    mysql> show create table xiaodi;
     ...
      CONSTRAINT `xiaodi_ibfk_1` FOREIGN KEY (`dage_id`) REFERENCES `dage` (`id`)
    ...
    mysql> alter table xiaodi drop foreign key xiaodi_ibfk_1; 
    Query OK, 1 row affected (0.04 sec)
    Records: 1  Duplicates: 0  Warnings: 
    mysql> alter table xiaodi add foreign key(dage_id) references dage(id) on delete cascade on update cascade;
    Query OK, 1 row affected (0.04 sec)
    Records: 1  Duplicates: 0  Warnings: 0
    
    # 然后再删大哥
    mysql> delete from dage where id=1;
    Query OK, 1 row affected (0.01 sec)
    
    mysql> select * from dage;
    Empty set (0.01 sec)
    
    mysql> select * from xiaodi;
    Empty set (0.00 sec)
    
    # 这个时候大哥和小弟就都被一套带走了。
    例子
  • 相关阅读:
    【项目管理和构建】十分钟教程,eclipse配置maven + 创建maven项目(三)
    【项目管理和构建】——Maven下载、安装和配置(二)
    【项目管理和构建】——Maven简介(一)
    Maven 环境变量设置
    【BZOJ282】【洛谷P3829 】【SHOI2012】—信用卡凸包(凸包)
    【BZOJ1076】【SCOI2008】—奖励关(期望+状压dp)
    【BZOJ3687】—简单题(bitset)
    【BZOJ2118】—墨墨的等式(最短路+背包)
    【BZOJ4300】—绝世好题(二进制dp)
    【洛谷P3345】【ZJOI2015】—幻想乡战略游戏(动态点分治)
  • 原文地址:https://www.cnblogs.com/kuxingseng95/p/9533491.html
Copyright © 2020-2023  润新知