1. 什么是约束(约束,非常重要,五颗星

    约束对应的英语单词:constraint
    在创建表的时候,我们可以给表中的字段加上一些约束,来保证这个表中数据的完整性、有效性!!!

    约束的作用就是为了保证:表中的数据有效!!!

    1. 约束包括那些

    非空约束:not null
    唯一性约束:unique
    主键约束:primary key (简称PK)
    外键约束:foreign key (简称FK)
    检查约束:check (MySQL不支持,oracle支持)

    我们这里重点学习四个约束:
    not null
    unique
    primary key
    foreign key

    1. 非空约束:not null

    not null只有列级约束,没有表级约束
    非空约束not null约束的字段不能为NULL。

    1. drop table if exists t_vip;
    2. create table t_vip(
    3. id int,
    4. name varchar(255) not null//name不能为就空
    5. );
    6. insert into t_vip(id,name) values(1,'zhangsan'),(2,'lisi');
    7. insert into t_vip(id) values(3);//报错,name不能为就空
    8. //Field 'name' doesn't have a default value

    小插曲:
    XXXx.sql这种文件被称为scr1脚本文件。
    sgl脚本文件中编写了大量的sq1语句。
    我们执行sql脚本文件的时候,该文件中所有的sql语句会全部执行!
    批量的执行sQL语句,可以使用sql脚本文件。
    在myscr1当中怎么执行sgl脚本呢?
    mysql> source D: \course\03-MysQL\ document\vip.sql

    你在实际的工作中,第一天到了公司,项目经理会给你一个xxx.sql文件,
    你执行这个脚本文件,你的电脑上的数据库数据就有了!!!

    1. 唯一性约束:unique

    唯一性约束unique约束的字段不能重复,但是可以为NULL。

    1. drop table if exists t_vip;
    2. create table t_vip(
    3. id int,
    4. name varchar(255) unique,
    5. email varchar(255)
    6. );
    7. insert into t_vip(id,name,email) values
    8. (1,'zhangsan','zhangsan@123.com'),
    9. (2,'lisi','lisi@123.com'),
    10. (3,'wangwu','wangwu@123.com');
    11. insert into t_vip(id,name,email) values(4,'wangwu','wangwu@qq.com');//错误,name为unique唯一性约束
    12. //Duplicate entry 'wangwu' for key 't_vip.name'
    13. insert into t_vip(id) values(4);
    14. insert into t_vip(id) values(5);
    15. +------+----------+------------------+
    16. | id | name | email |
    17. +------+----------+------------------+
    18. | 1 | zhangsan | zhangsan@123.com |
    19. | 2 | lisi | lisi@123.com |
    20. | 3 | wangwu | wangwu@123.com |
    21. | 4 | NULL | NULL |
    22. | 5 | NULL | NULL |
    23. +------+----------+------------------+
    24. name字段虽然被unique约束,但是可以为NULL

    新需求:name与email两个字段联合起来具有唯一性

    drop table if exists t_vip;
    create table t_vip(
        id int,
        name varchar(255) unique,
        email varchar(255) unique
    );
    这张表这样创建是不符合以上"新需求"的
    这样创建表示:name具有唯一性,email具有唯一性,各自唯一
    
    以下这样的数据是符合"新需求"的 
    但如果采用以上方式创建表的话,肯定创建失败,因为'zhangsan'和'zhangsan'重了
    insert into t_vip(id,name,email) values
    (1,'zhangsan','zhangsan@123.com'),
    (2,'zhangsan','zhangsan@sina.com');
    
    满足"新需求"应该这样创建:
    drop table if exists t_vip;
    create table t_vip(
        id int,
        name varchar(255),
        email varchar(255),
        unique(name,email)
    );
    //unique(name,email)表示name和email两个字段联合起来唯一!!!
    insert into t_vip(id,name,email) values(3,'zhangsan','zhangsan@123.com');
    //错误:Duplicate entry 'zhangsan-zhangsan@123.com' for key 't_vip.name'
    

    name varchar(255) unique,约束直接插在列后面,这种叫列级约束
    unique(name,email)约束没有添加在列后面,这种约束叫做表级约束
    什么时候使用表级约束
    需要给多个字段联合起来添加一个约束的时候,需要使用表级约束

    not null 可以和unique联合使用

    drop table if exists t_vip;
    create table t_vip(
        id int,
        name varchar(255) not null unique
    );
    +-------+--------------+------+-----+---------+-------+
    | Field | Type         | Null | Key | Default | Extra |
    +-------+--------------+------+-----+---------+-------+
    | id    | int          | YES  |     | NULL    |       |
    | name  | varchar(255) | NO   | PRI | NULL    |       |
    +-------+--------------+------+-----+---------+-------+
    
    insert into t_vip(id,name) values(1,'zhangsan');
    insert into t_vip(id,name) values(2,'zhangsan');//错误,name不能重复
    insert into t_vip(id) values(3);//错误,name不能为NULL
    

    在MySQL当中,如果一个字段同时被not null 和unique约束的话,该字段自动变为主键字段。(注意:oracle中不一样!

    1. 主键约束(primary key,简称pk)(非常重要,五颗星*

    主键约束的相关术语
    主键约束:就是一种约束
    主键字段:该字段添加上了主键约束,这样的字段叫做:主键字段
    主键值:主键字段中的每一个值都叫做主键值

    什么是主键,有啥用?
    主键值是每一行记录的唯一标识
    主键值是每一行记录的身份证号!!

    记住:任何一张表都应该有主键,没有主键,表无效!!!

    主键的特征:not null + unique(主键值不能为NULL,同时也不能重复)(可以类比于身份证号来理解)

    怎么给一张表添加主键约束呢

    drop table if exists t_vip;
    //一个字段做主键,叫做单一主键
    create table t_vip(
        id int primary key,//列级约束
        name varchar(255) 
    );
    insert into t_vip(id,name) values(1,'zhangsan');
    insert into t_vip(id,name) values(2,'lisi');
    
    //错误,id为主键,不能重复
    insert into t_vip(id,name) values(2,'wangwu');
    // Duplicate entry '2' for key 't_vip.PRIMARY'
    
    //错误,id为主键,不能为NULL
    insert into t_vip(name) values('zhaoliu');
    // Field 'id' doesn't have a default value
    
    可以使用表级约束来添加主键
    drop table if exists t_vip;
    create table t_vip(
        id int ,
        name varchar(255),
        primary key(id)//表级约束
    );
    
    drop table if exists t_vip;
    //id和email联合起来做主键,叫做复合主键
    create table t_vip(
        id int ,
        name varchar(255),
        email varchar(255),
        primary key(id,name)
    );
    insert into t_vip(id,name,email) values(1,'zhangsan','zhangsan@123.com');
    insert into t_vip(id,name,email) values(1,'lisi','lisi@123.com');
                    +----+----------+------------------+
                    | id | name     | email            |
                    +----+----------+------------------+
                    |  1 | lisi     | lisi@123.com     |
                    |  1 | zhangsan | zhangsan@123.com |
                    +----+----------+------------------+
    
    //错误,不能重复
    insert into t_vip(id,name,email) values(1,'lisi','lisi@sina.com');
    //Duplicate entry '1-lisi' for key 't_vip.PRIMARY'
    
    在实际开发中不建议使用复合主键,建议使用单一主键
    因为主键存在的意义就是这行记录的身份证号,只要意义达到即可
    
    一个表中主键约束能加两个吗
    drop table if exists t_vip;
    create table t_vip(
        id int primary key,
        name varchar(255) primary key
    );
    //错误,不能定义多个主键
    //Multiple primary key defined
    

    结论:一张表,主键约束只能添加一个

    主键值建议使用:
    int
    bigint
    char
    等类型
    不建议使用:varchar来做主键。主键值一般都是数字,一般都是定长的

    主键除了:单一主键和复合主键之外,还可以这样分类
    自然主键:主键值就是一个自然数,和业务没关系
    业务主键:主键值和业务紧密关联,例如拿银行卡账号做主键值。这就是业务主键!!

    在实际开发中使用业务主键多,还是自然主键多
    自然主键使用比较多,因为主键只要做到不重复就行,不需要有意义
    业务主键不好,因为主键一旦和业务挂钩,那么当业务发生变动的时候,
    可能会影响到主键值,所以业务主键不建议使用,尽量使用自然主键

    在mysql当中,有一种机制,可以帮助我们自动维护一个主键值

    drop table if exists t_vip;
    create table t_vip(
      id int primary key auto_increment,//auto_increment表示自增,从1开始,以1递增
      name varchar(255)
    );
    insert into t_vip(name) values('zhangsan');
    insert into t_vip(name) values('zhangsan');
    insert into t_vip(name) values('zhangsan');
    insert into t_vip(name) values('zhangsan');
    insert into t_vip(name) values('zhangsan');
    insert into t_vip(name) values('zhangsan');
    insert into t_vip(name) values('zhangsan');
    insert into t_vip(name) values('zhangsan');
                    +----+----------+
                    | id | name     |
                    +----+----------+
                    |  1 | zhangsan |
                    |  2 | zhangsan |
                    |  3 | zhangsan |
                    |  4 | zhangsan |
                    |  5 | zhangsan |
                    |  6 | zhangsan |
                    |  7 | zhangsan |
                    |  8 | zhangsan |
                    +----+----------+
    
    1. 外键约束(foreign key,简称FK)非常重要五颗星*

    外键约束涉及到的相关术语:
    外键约束:一种约束(foreign key)
    外键字段:该字段添加上了外键约束
    外键值:外键字段当中的每一个值

     业务背景:
        请设计数据库表,用来维护"班级和学生"的信息?
        第一种方案:一张表存储所有数据
        t_student
    no(pk)            name          classno            classname
    ----------------------------------------------------------------------------
    1                Jack            100        北京大兴区经济技术开发区亦庄二中高三1班
    2                Lucy            100        北京大兴区经济技术开发区亦庄二中高三1班
    3                lilei            100        北京大兴区经济技术开发区亦庄二中高三1班
    4              hanmeimei            100        北京大兴区经济技术开发区亦庄二中高三1班
    5              zhangsan            101        北京大兴区经济技术开发区亦庄二中高三2班
    6                 lisi            101        北京大兴区经济技术开发区亦庄二中高三2班
    7               wanwgwu            101        北京大兴区经济技术开发区亦庄二中高三2班
    8               zhaoliu            101        北京大兴区经济技术开发区亦庄二中高三2班
    
                缺点:数据冗余,空间浪费。【不推荐】
                这个设计比较失败
    
        第二种方案:两张表(班级表和学生表)
        t_class 班级表
        classno(pk)            classname
        --------------------------------------------------------
        100        北京大兴区经济技术开发区亦庄二中高三1班
        101        北京大兴区经济技术开发区亦庄二中高三2班
    
        t_student 学生表
        no(pk)            name                cno(FK引用t_class这张表的classno)
        ------------------------------------------------------------
        1                Jack                100
        2                Lucy                100
        3                lilei                100
        4                hanmeimei            100
        5                zhangsan            101
        6                 lisi                101
        7                wangwu                101
        8                zhaoliu                101
    

    当cno字段没有任何约束的时候,可能会导致数据的无效,可能出现一个102,但102班级不存在,所以为了保证cno字段中的值都是100和101,需要给cno字段添加外键约束]
    那么:cno字段就是外键字段,cno字段中的每一个值都是外键值

    被引用的表被称为父表
    引用表的表被称为子表
    注意:
    t_class是父表
    t_student是子表

    删除表的顺序:
    先删子表,再删父表
    创建表的顺序:
    先创建父表, 再创建子表
    删除数据的顺序:
    先删子表,再删父表
    插入数据的顺序:
    先插入父表,再插入子表

    drop table if exists t_student;
    drop table if exists t_class;
    create table t_class(
        classno int primary key,
        classname varchar(255)
    );
    create table t_student(
        no int primary key auto_incr dement,
        name varchar(255),
        cno int,
        foreign key(cno) references t_class(classno) 
    );
    insert into t_class(classno,classname) values
    (100,'北京大兴区经济技术开发区亦庄二中高三1班'),
    (101,'北京大兴区经济技术开发区亦庄二中高三2班');
    insert into t_student(name,cno) values('Jack',100);
    insert into t_student(name,cno) values('Lucy',100);
    insert into t_student(name,cno) values('lilei',100);
    insert into t_student(name,cno) values('hanmeimei',100);
    insert into t_student(name,cno) values('zhangsan',101);
    insert into t_student(name,cno) values('lisi',101);
    insert into t_student(name,cno) values('wangwu',101);
    insert into t_student(name,cno) values('zhaoliu',101);
    

    思考:子表中的外键引用的父表中的某个字段,被引用的这个字段必须是主键吗?
    不一定是主键,但至少必须具有唯一性(unique约束)
    测试:外键可以为NULL吗?
    insert into t_student(name) values(‘wangliu’);
    | 9 | wangliu | NULL |
    外键值可以为NULL