Python进阶----数据库引擎(InnoDB),表的创建,mysql的数据类型,mysql表的约束

时间:2022-09-21 11:36:32

Python进阶----数据库引擎(InnoDB),表的创建,mysql的数据类型,mysql表的约束

一丶MySQL的存储引擎

什么是存储引擎:

   MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能。

例如,如果你在研究大量的临时数据,你也许需要使用内存存储引擎。内存存储引擎能够在内存中存储所有的表格数据。又或者,你也许需要一个支持事务处理的数据库(以确保事务处理不成功时数据的回退能力)。

这些不同的技术以及配套的相关功能在MySQL中被称作存储引擎(也称作表类型)。

   MySQL默认配置了许多不同的存储引擎,可以预先设置或者在MySQL服务器中启用。你可以选择适用于服务器、数据库和表格的存储引擎,以便在选择如何存储你的信息、如何检索这些信息以及你需要你的数据结合什么性能和功能的时候为你提供最大的灵活性。

   选择如何存储和检索你的数据的这种灵活性是MySQL为什么如此受欢迎的主要原因。其它数据库系统(包括大多数商业选择)仅支持一种类型的数据存储

   遗憾的是,其它类型的数据库解决方案采取的“一个尺码满足一切需求”的方式意味着你要么就牺牲一些性能,要么你就用几个小时甚至几天的时间详细调整你的数据库。使用MySQL,我们仅需要修改我们使用的存储引擎就可以了

​      存储引擎:存储文件的一种方式,不同的存储引擎存储数据是不同的.

myql默认支持哪些引擎:

   mysql5.6支持的存储引擎包括InnoDB、MyISAM、MEMORY、CSV、BLACKHOLE、FEDERATED、MRG_MYISAM、ARCHIVE、PERFORMANCE_SCHEMA。其中NDB和InnoDB提供事务安全表,其他存储引擎都是非事务安全表。

   查看所有mysql所有引擎:

Python进阶----数据库引擎(InnoDB),表的创建,mysql的数据类型,mysql表的约束

   各种引擎的介绍:????

# InnoDB

MySql 5.6 版本默认的存储引擎。InnoDB 是一个事务安全的存储引擎,它具备提交、回滚以及崩溃恢复的功能以保护用户数据。InnoDB 的行级别锁定以及 Oracle 风格的一致性无锁读提升了它的多用户并发数以及性能。InnoDB 将用户数据存储在聚集索引中以减少基于主键的普通查询所带来的 I/O 开销。为了保证数据的完整性,InnoDB 还支持外键约束。

# MyISAM

MyISAM既不支持事务、也不支持外键、其优势是访问速度快,但是表级别的锁定限制了它在读写负载方面的性能,因此它经常应用于只读或者以读为主的数据场景。

# Memory

在内存中存储所有数据,应用于对非关键数据由快速查找的场景。Memory类型的表访问数据非常快,因为它的数据是存放在内存中的,并且默认使用HASH索引,但是一旦服务关闭,表中的数据就会丢失

# BLACKHOLE

黑洞存储引擎,类似于 Unix 的 /dev/null,Archive 只接收但却并不保存数据。对这种引擎的表的查询常常返回一个空集。这种表可以应用于 DML 语句需要发送到从服务器,但主服务器并不会保留这种数据的备份的主从配置中。

# CSV

它的表真的是以逗号分隔的文本文件。CSV 表允许你以 CSV 格式导入导出数据,以相同的读和写的格式和脚本和应用交互数据。由于 CSV 表没有索引,你最好是在普通操作中将数据放在 InnoDB 表里,只有在导入或导出阶段使用一下 CSV 表。

# NDB

(又名 NDBCLUSTER)——这种集群数据引擎尤其适合于需要最高程度的正常运行时间和可用性的应用。注意:NDB 存储引擎在标准 MySql 5.6 版本里并不被支持。目前能够支持

MySql 集群的版本有:基于 MySql 5.1 的 MySQL Cluster NDB 7.1;基于 MySql 5.5 的 MySQL Cluster NDB 7.2;基于 MySql 5.6 的 MySQL Cluster NDB 7.3。同样基于 MySql 5.6 的 MySQL Cluster NDB 7.4 目前正处于研发阶段。

# Merge

允许 MySql DBA 或开发者将一系列相同的 MyISAM 表进行分组,并把它们作为一个对象进行引用。适用于超大规模数据场景,如数据仓库。

# Federated

提供了从多个物理机上联接不同的 MySql 服务器来创建一个逻辑数据库的能力。适用于分布式或者数据市场的场景。


# Example

这种存储引擎用以保存阐明如何开始写新的存储引擎的 MySql 源码的例子。它主要针对于有兴趣的开发人员。这种存储引擎就是一个啥事也不做的 "存根"。你可以使用这种引擎创建表,但是你无法向其保存任何数据,也无法从它们检索任何索引。

存储引擎的特性:

   1.并发性:开发某些程序比其应用程序具有很多的颗粒剂锁定要求(行级锁)

   2.事务支持性:并非所有的应用程序都需要事务,但对需要事务的应用来说,有着定义良好的需求

   3.引用完整性:通过DDL定义的外键,服务器需要强制保持关联数据库的引用完整性

   4.物理存储:包括各种的事项,从表的索引的总的页大小,到存储数据所需的格式,到物理磁盘

   5.索引支持:不同的应用程序更倾向于采用不同的索引策略,每种存储引擎通常有自己的编制索引的方式.但某些索引方法(如B-tree索引)对几乎所有的存储引擎来说是共同的

​   6.内存告诉缓冲:与其他应用程序相比,不同的应用程序对某些内存高速缓冲策略的响应更好,因此,,尽管某些内存高速缓冲对所有存储引擎来说是共同的(如:用户连接高速缓冲,mysql的高速查询高速缓冲等.),其他高速缓冲策略仅当使用特殊的存储引擎时才唯一定义

   7.性能帮助:针对并行操作的多I/O线程,线程并发性.数据库检查点,成批插入等

   8.其他目标特性:可能包括对地理空间操作的支持,对特定数据处理操作的安全限制等.

#以上要求会在不同的需求中予以体现,通过单独一个系统实现是不可能的,以上特点有些本身就是相互矛盾的,鱼和熊掌的问题。对以上内容做些选择,形成的存储引擎就是一个插件引擎了,某些特定的需求可以使用

mysql常用的存储引擎:

      InnoDB应用场景及特点:

         用于事务处理应用程序,支持外键和行级锁.如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包括很多更新和删除操作,使用InnoDB存储引擎是比较合适的.InnoDB除了有效的降低由删除和更新导致的锁定,还可确保事务的完整提交和回滚,对于类似计费系统或者财务系统等对数据准确要求性比较高的系统都是适合的选择.

### InnoDB的缩略特点:如下????

    # 2个文件夹(.frm存放表结构  ,  .ibd存放数据)
        
    # mysql5.6以上 默认的存储方式

    # transaction 事务   保证数据安全 数据的完整性而设置的概念

    # row-level locking 行级锁

    # table-level locking 表级锁

    # foreign keys 外键约束

    # 树tree - 加速查询 (树形结构(数据+树) + 表结构)
# 创建 engine引擎为InnoDB的数据表
create table Innodb_t (id int,name char(18)) engine=InnoDB;

# 查看表结构
show create table innodb_t;
 # 结果: ENGINE=InnoDB

​      MyISAM应用场景和特点:

         是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不太高

### 缩略特点:
    # 3个文件夹(.frm存放表结构  ,  .MYD存放数据, .MYI存放树形结构)
        
    # mysql5.5以下 默认的存储方式
    
    # table-level locking 表级锁
    
    # 树tree - 加速查询 (树形结构 + 数据 + 表结构)
# 创建 engine引擎为mysiam的数据表
create table myisam_t (id int,name char(18)) engine=myisam

# 查看表结构
show create table myisam_t;
 # 结果: ENGINE=MyISAM

      Memory:

         将所有的数据保存在内存中,在需要快速定位记录和其他类似数据的环境下,可以提供极快的访问。Memory的缺陷是对表的大小有限制,虽然数据库因为异常终止的话数据可以正常恢复,但是一旦数据库关闭,存储在内存中的数据都会丢失。

### 缩略特点:
    # 1个文件夹(.frm存放表结构 ) ,数据放在内存中
    
    # 基于hash
# 创建 engine引擎为memory的数据表
create table memory_t (id int,name char(18)) engine=memory;

# 查看表结构
show create table memory_t;
 # 结果: ENGINE=MEMORY

​      修改表引擎:

# 修改表引擎
alter table memory_t  engine = innodb;
# 查看结果
show create table memory_t;

​ 文件形式配置引擎:

#my.ini文件
[mysqld]
default-storage-engine=INNODB

mysql工作流程:

   MySQL架构总共四层,在上图中以虚线作为划分。
       首先,最上层的服务并不是MySQL独有的,大多数给予网络的客户端/服务器的工具或者服务都有类似的架构。比如:连接处理、授权认证、安全等。
       第二层的架构包括大多数的MySQL的核心服务。包括:查询解析、分析、优化、缓存以及所有的内置函数(例如:日期、时间、数学和加密函数)。同时,所有的跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。

       第三层包含了存储引擎。存储引擎负责MySQL中数据的存储和提取。服务器通过API和存储引擎进行通信。这些接口屏蔽了不同存储引擎之间的差异,使得这些差异对上层的查询过程透明化。存储引擎API包含十几个底层函数,用于执行“开始一个事务”等操作。但存储引擎一般不会去解析SQL(InnoDB会解析外键定义,因为其本身没有实现该功能),不同存储引擎之间也不会相互通信,而只是简单的响应上层的服务器请求。

       第四层包含了文件系统,所有的表结构和数据以及用户操作的日志最终还是以文件的形式存储在硬盘上

Python进阶----数据库引擎(InnoDB),表的创建,mysql的数据类型,mysql表的约束

二丶表的操作

创建表语法:

#语法:
create table 表名(
字段名1 类型[(宽度) 约束条件],
字段名2 类型[(宽度) 约束条件],
字段名3 类型[(宽度) 约束条件]
);

#注意:
1. 在同一张表中,字段名是不能相同
2. 宽度和约束条件可选
3. 字段名和类型是必须的

创建表和查看表结构:

######## cmd 命令行模式执行????:
# 1. 创建数据库 
create database staff;

# 2. 使用数据库
use staff

# 3. 创建表
create table staff_info (
    id int,name varchar(50),
    age int(3),
    sex enum('male','female'),
    phone bigint(11),
    job varchar(11)
);

# 4. 查看表结构
desc staff_info

# 5. 增加数据
 insert into staff_info (id,name,age,sex,phone,job) values  (1,'lisi',83,'female',13651054608,'IT');
 
# 6. 查询数据 
select * from staff_info;

三丶MySQL中常用的数据类型

数值类型:

​      常用数值类型:tinyin , int 和 float(四舍五入)

类型 大小 范围(有符号) 范围(无符号)unsigned约束 用途
TINYINT 1 字节 (-128,127) (0,255) 小整数值
SMALLINT 2 字节 (-32 768,32 767) (0,65 535) 大整数值
MEDIUMINT 3 字节 (-8 388 608,8 388 607) (0,16 777 215) 大整数值
INT或INTEGER 4 字节 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值
BIGINT 8 字节 (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值
FLOAT 4 字节float(255,30) (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 单精度 浮点数值
DOUBLE 8 字节double(255,30) (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度 浮点数值
DECIMAL 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2double(65,30) 依赖于M和D的值 依赖于M和D的值 小数值

      int类型实例:

# 1. 创建一个t1表 
    create table t1(id1 int ,id2 int(5));

# 2. 查看 t1 表结构  , int默认给11个宽度 , 但与实际可存的值不一样.
    desc t1;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id1   | int(11) | YES  |     | NULL    |       |
| id2   | int(5)  | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+

    select * from t1; 
+------------+--------+
| id1        | id2    |
+------------+--------+
| 0000000001 |  00001 |
| 0000111111 | 111111 |
+------------+--------+

# 3.增加数据.
mysql> insert into t1 values(111111,11111111);

# 4.t1表 id1 字段 修改 添加unsigned无符号约束
mysql> alter table t1 modify id1 int unsigned;
    # 结果:
    Query OK, 5 rows affected (0.70 sec)
    Records: 5  Duplicates: 0  Warnings: 0

# 5. 再次查看表结构
mysql> desc t1;
+-------+------------------+------+-----+---------+-------+
| Field | Type             | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+-------+
| id1   | int(10) unsigned | YES  |     | NULL    |       |
| id2   | int(5)           | YES  |     | NULL    |       |
+-------+------------------+------+-----+---------+-------+

# 6. 再次添加数据, 无符号unsigned修饰的id1可存4294967295
mysql> insert into t1(id1) values (4294967295);
mysql> select * from t1;
+------------+------------+
| id1        | id2        |
+------------+------------+
| 4294967295 |       NULL |
+------------+------------+

# 7. 有符号的只能存 -2147483648 ~ +2147483647 
mysql> insert into t1 values(-2147483648,2147483647);
Query OK, 1 row affected (0.12 sec)

mysql> insert into t1 values(-2147483649,2147483647);
ERROR 1264 (22003): Out of range value for column 'id1' at row 1

mysql> insert into t1 values(-2147483648,2147483648);
ERROR 1264 (22003): Out of range value for column 'id2' at row 1
mysql>

      小数实例:

​         float(5,2):表示一共5位,小数点后保留2位

# 1 .创建t2表 float double decimal 三个字段
mysql> create table t2 (id1 float(5,2),id2 double(5,2),id3 decimal(5,2));
Query OK, 0 rows affected (0.34 sec)

# 2 .查看表结构
mysql> desc t2;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id1   | float(5,2)   | YES  |     | NULL    |       |
| id2   | double(5,2)  | YES  |     | NULL    |       |
| id3   | decimal(5,2) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

# 3.添加数据   
mysql> insert into t2 values (1.234567,1.234567,1.234567);
Query OK, 1 row affected, 1 warning (0.12 sec)
    # 不难发现都被截断了. (5,2)表示一共5位,小数点后保留2位,剩余的3位是小数点前
mysql> select * from t2;
+------+------+------+
| id1  | id2  | id3  |
+------+------+------+
| 1.23 | 1.23 | 1.23 |
+------+------+------+
1 row in set (0.00 sec)

# 4. 四舍五入 小数点后两位保留,根据下一位进项四舍五入
mysql> insert into t2 values (1.235567,1.235567,1.235567);
Query OK, 1 row affected, 1 warning (0.11 sec)

mysql> select * from t2;
+------+------+------+
| id1  | id2  | id3  |
+------+------+------+
| 1.23 | 1.23 | 1.23 |
| 1.24 | 1.24 | 1.24 |
+------+------+------+
2 rows in set (0.00 sec)


# 5. 去掉约束创建t3表   , decimal默认是(10,0) 
mysql> create table t3 (id1 float,id2 double,id3 decimal);
Query OK, 0 rows affected (0.32 sec)

mysql> desc t3;
+-------+---------------+------+-----+---------+-------+
| Field | Type          | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| id1   | float         | YES  |     | NULL    |       |
| id2   | double        | YES  |     | NULL    |       |
| id3   | decimal(10,0) | YES  |     | NULL    |       |
+-------+---------------+------+-----+---------+-------+
3 rows in set (0.01 sec)


# 6. decimal默认取整
mysql>  insert into t3 values (1.234,1.234,1.234);
Query OK, 1 row affected, 1 warning (0.12 sec)

mysql> select * from t3;
+-------+-------+------+
| id1   | id2   | id3  |
+-------+-------+------+
| 1.234 | 1.234 |    1 |
+-------+-------+------+
1 row in set (0.00 sec)

# 7. 当对小数位没有约束的时候,输入超长的小数,会发现float和double的区别
    # float默认保留小数点后 5位
    # double默认保留小数点后 16位
    
mysql>  insert into t3 values (1.2355555555555555555,1.2355555555555555555,1.2355555555555555555555);
Query OK, 1 row affected, 1 warning (0.11 sec)

mysql> select * from t3;
+---------+--------------------+------+
| id1     | id2                | id3  |
+---------+--------------------+------+
|   1.234 |              1.234 |    1 |
| 1.23556 | 1.2355555555555555 |    1 |
+---------+--------------------+------+
2 rows in set (0.00 sec)

时间日期类型

      常用: date

类型 大小 (字节) 范围 格式 用途 应用场景
DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 年月日 员工生日
TIME 3 '-838:59:59'/'838:59:59' HH:MM:SS 时分秒 每天固定某一时刻的任务
YEAR 1 1901/2155 YYYY 年份值 年份(酒年份)
DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 年月日时分秒 日志/博客评论
TIMESTAMP 4 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和时间值,时间戳 范围只能到2038年,使用少

​ 日期案例:

# 1. 创建 t4表, 存放各种日期类型
mysql> create table t4(d date ,t time ,dt datetime,y year,ts timestamp);
mysql> desc t4;
+-------+-----------+------+-----+-------------------+-----------------------------+
| Field | Type      | Null | Key | Default           | Extra                       |
+-------+-----------+------+-----+-------------------+-----------------------------+
| d     | date      | YES  |     | NULL              |                             |
| t     | time      | YES  |     | NULL              |                             |
| dt    | datetime  | YES  |     | NULL              |                             |
| y     | year(4)   | YES  |     | NULL              |                             |
| ts    | timestamp | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+-----------+------+-----+-------------------+-----------------------------+
5 rows in set (0.01 sec)


# 2. 添加数据  now()聚合函数,由mysql数据库提供,获取当前时间.
        ## timestamp 类型的数据 被约束了, 默认获取当前时间,不能为空
        ## ts字段 插入数据null,会自动插入当前时间的时间
        ## 其他类型的数据 按照类型截取自己需要的时间.
mysql> insert into t4 values (now(),now(),now(),now(),null );
Query OK, 1 row affected, 1 warning (0.11 sec)

mysql> select * from t4;
+------------+----------+---------------------+------+---------------------+
| d          | t        | dt                  | y    | ts                  |
+------------+----------+---------------------+------+---------------------+
| 2019-07-30 | 17:28:11 | 2019-07-30 17:28:11 | 2019 | 2019-07-30 17:28:11 |
+------------+----------+---------------------+------+---------------------+
1 row in set (0.00 sec)


# 3. 手动添加datetime数据类型
    #格式: 2018-9-26 12:20:10 或者,2018/9/26 12+20+10 或者,20180926122010 或者,20180926122010
    
    mysql>  insert into t4(dt) values (20180926122010);
    mysql>  insert into t4(dt) values ('2018/9/26 12+20+10');
    mysql>  insert into t4(dt) values ('2018-9-26 12:20:10');
    mysql> select * from t4;
    +------------+----------+---------------------+------+---------------------+
    | d          | t        | dt                  | y    | ts                  |
    +------------+----------+---------------------+------+---------------------+
    | 2019-07-30 | 17:28:11 | 2019-07-30 17:28:11 | 2019 | 2019-07-30 17:28:11 |
    | NULL       | NULL     | 2018-09-26 12:20:10 | NULL | 2019-07-30 17:35:00 |
    | NULL       | NULL     | 2018-09-26 12:20:10 | NULL | 2019-07-30 17:35:21 |
    | NULL       | NULL     | 2018-09-26 12:20:10 | NULL | 2019-07-30 17:35:53 |
    +------------+----------+---------------------+------+---------------------+
    
    # 但是 数值类型的长度必须是20180926122010 14位, 少一位都不行
    mysql>  insert into t4(dt) values (2018092612201);
    ERROR 1292 (22007): Incorrect datetime value: '2018092612201' for column 'dt' at row 1
    
    # 字符串不限制,默认为0
    mysql>  insert into t4(dt) values ('2018-9-26 12:20');
    mysql> select * from t4;
    +------------+----------+---------------------+------+---------------------+
    | d          | t        | dt                  | y    | ts                  |
    +------------+----------+---------------------+------+---------------------+
    | NULL       | NULL     | 2018-09-26 12:20:00 | NULL | 2019-07-30 17:38:40 |
    +------------+----------+---------------------+------+---------------------+


# 4. 修改某条记录时,timestamp自动更新
    mysql> select * from t4;
    +------------+----------+---------------------+------+---------------------+
    | d          | t        | dt                  | y    | ts                  |
    +------------+----------+---------------------+------+---------------------+
    | 2019-07-30 | 17:28:11 | 2019-07-30 17:28:11 | 2019 | 2019-07-30 17:28:11 |
    +------------+----------+---------------------+------+---------------------+
    
    Query OK, 1 row affected (0.12 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    # 查看数据,发现字段 ts是timestamp 类型数据 时间被更新了.
    mysql> select * from t4;
    +------------+----------+---------------------+------+---------------------+
    | d          | t        | dt                  | y    | ts                  |
    +------------+----------+---------------------+------+---------------------+
    | 2019-07-30 | 17:28:11 | 2019-07-30 17:28:11 | 2020 | 2019-07-30 17:48:06 |
    +------------+----------+---------------------+------+---------------------+

    原因:  对 ts字段 做了约束(NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)
    mysql> show create table t4;
    +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Table | Create Table                                                                                                                                                                                                                                         |
    +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | t4    | CREATE TABLE `t4` (
      `d` date DEFAULT NULL,
      `t` time DEFAULT NULL,
      `dt` datetime DEFAULT NULL,
      `y` year(4) DEFAULT NULL,
      `ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
    +-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+


    
# 5. 手动添加data数据类型
    mysql>  insert into t4(d) values ('2018-12-12');
    Query OK, 1 row affected (0.11 sec)
        # 但只截取 年月日
    mysql>  insert into t4(d) values ('2018-12-12 12:12:12');
    Query OK, 1 row affected, 1 warning (0.04 sec)
    +------------+----------+---------------------+------+---------------------+
    | d          | t        | dt                  | y    | ts                  |
    +------------+----------+---------------------+------+---------------------+
    | 2018-12-12 | NULL     | NULL                | NULL | 2019-07-30 17:45:04 |
    | 2018-12-12 | NULL     | NULL                | NULL | 2019-07-30 17:45:12 |
    +------------+----------+---------------------+------+---------------------+



# 6. 手动添加year数据类型
    mysql>  insert into t4(y) values ('2018');
    mysql> select * from t4;
    +------------+----------+---------------------+------+---------------------+
    | d          | t        | dt                  | y    | ts                  |
    +------------+----------+---------------------+------+---------------------+
    | NULL       | NULL     | NULL                | 2018 | 2019-07-30 17:41:12 |
    +------------+----------+---------------------+------+---------------------+

字符串类型

​      定义:

         CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。

类型 大小 用途
CHAR 0-255字节 定长字符串
VARCHAR 0-65535 字节 变长字符串
TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串
TINYTEXT 0-255字节 短文本字符串
BLOB 0-65 535字节 二进制形式的长文本数据
TEXT 0-65 535字节 长文本数据
MEDIUMBLOB 0-16 777 215字节 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16 777 215字节 中等长度文本数据
LONGBLOB 0-4 294 967 295字节 二进制形式的极大文本数据
LONGTEXT 0-4 294 967 295字节 极大文本数据

         char和varchar案例:

# 1. 创建 t5 表,  并 查询表结构, 不难发现 char默认是1个字符
    ## char的长度是0-255字符,  varchar的长度是0-65535个字符.
    
    mysql> create table t5(c1 char, c2 char(5), vc varchar(5));
    Query OK, 0 rows affected (0.30 sec)

    mysql> desc t5;
    +-------+------------+------+-----+---------+-------+
    | Field | Type       | Null | Key | Default | Extra |
    +-------+------------+------+-----+---------+-------+
    | c1    | char(1)    | YES  |     | NULL    |       |
    | c2    | char(5)    | YES  |     | NULL    |       |
    | vc    | varchar(5) | YES  |     | NULL    |       |
    +-------+------------+------+-----+---------+-------+
    

# 2. 增加数据  
    # 字符
    mysql> insert into t5 values('a','abcd','abcd');
    
    ## 支持 中文
    mysql> insert into t5 values('你','欢迎你啊亲','欢迎你啊秦');
    mysql> select * from t5;
    +------+-----------------+-----------------+
    | c1   | c2              | vc              |
    +------+-----------------+-----------------+
    | a    | abcd            | abcd            |
    | 你   | 欢迎你啊亲      | 欢迎你啊秦        |
    +------+-----------------+-----------------+
    
    ## 错误  , 原因: 增加的字符长度不能炒锅设定长度.
    mysql> insert into t5 values('abcdef','abcdef','abcdef');
    ERROR 1406 (22001): Data too long for column 'c1' at row 1
    mysql> insert into t5 values('a','abcdef','abcdef');
    ERROR 1406 (22001): Data too long for column 'c2' at row 1
    mysql> insert into t5 values('a','abcd5','abcdef');
    ERROR 1406 (22001): Data too long for column 'vc' at row 1
    mysql> insert into t5 values('a','abcd','abcdef');
    ERROR 1406 (22001): Data too long for column 'vc' at row 1
    

# 3. char添加的时候回自动去除两端的空格, varchar不会去空格
    mysql> insert into t5 values('a','ab  ','ab  ');    # char(c2):2  varchar(vc):4
    mysql> insert into t5 values('a','a b ','ab  ');    # char(c2):3  varchar(vc):4 
    
    # 查看长度
    mysql> select length(c2) ,length(vc) from t5;
    +------------+------------+
    | length(c2) | length(vc) |
    +------------+------------+
    |          2 |          4 |
    |          3 |          4 |
    +------------+------------+
    
    # 给查询的拼接上 + 号
    mysql> select concat(c2,'+'),concat(vc,'+') from t5;
    +------------------+------------------+
    | concat(c2,'+')   | concat(vc,'+')   |
    +------------------+------------------+
    | ab+              | ab  +            |
    | a b+             | ab  +            |
    +------------------+------------------+

# 4. 存储长度超过定义长度 ,会截断
    mysql> insert into t5 values('a','abcde ','abcde    ');
    Query OK, 1 row affected, 1 warning (0.11 sec)

    mysql> insert into t5 values('a','abcde ','abcde    ');
    Query OK, 1 row affected, 1 warning (0.03 sec)

    mysql> select length(c2) ,length(vc) from t5;
    +------------+------------+
    | length(c2) | length(vc) |
    +------------+------------+
    |          5 |          5 |
    |          5 |          5 |
    +------------+------------+

ENUM和SET类型

​      定义:

         ENUM中文名称叫枚举类型,它的值范围需要在创建表时通过枚举方式显示。ENUM只允许从值集合中选取单个值,而不能一次取多个值

         SET和ENUM非常相似,也是一个字符串对象,里面可以包含0-64个成员。根据成员的不同,存储上也有所不同。set类型可以允许值集合中任意选择1或多个元素进行组合。对超出范围的内容将不允许注入,而对重复的值将进行自动去重。

类型 大小 用途
ENUM 对1-255个成员的枚举需要1个字节存储;对于255-65535个成员,需要2个字节存储;最多允许65535个成员。 单选:选择性别
SET 1-8个成员的集合,占1个字节9-16个成员的集合,占2个字节17-24个成员的集合,占3个字节25-32个成员的集合,占4个字节33-64个成员的集合,占8个字节 多选:兴趣爱好

​      set/enum案例

# 1. 创建 t6表, gender 字段 enum数据类   ,查勘表结构
    mysql> create table t6 (name char(20) ,gender enum('男','女'));
    Query OK, 0 rows affected (0.32 sec)
    mysql> desc t6;
    +--------+-------------------+------+-----+---------+-------+
    | Field  | Type              | Null | Key | Default | Extra |
    +--------+-------------------+------+-----+---------+-------+
    | name   | char(20)          | YES  |     | NULL    |       |
    | gender | enum('男','女')   | YES  |     | NULL    |       |
    +--------+-------------------+------+-----+---------+-------+

# 2. t6表, gender 增加数据
    # enum 是单选   ,enum('男','女') 只能选择一个项添加到数据库
    mysql> insert into t6 values('alex','男');
    mysql> select * from t6;
    +------+--------+
    | name | gender |
    +------+--------+
    | alex | 男     |
    +------+--------+
    
    # 错误示例 不能同时插入'男','女'两个值,也不能插入不属于'男','女'的值
    mysql> insert into t6 values('alexsb','男,女');
    ERROR 1265 (01000): Data truncated for column 'gender' at row 1
    
    
# 3. 创建 t7 表, 设置hobby字段 是set类型 ,可多选
    mysql> create table t7 (name char(20),hobby set('抽烟','喝酒','烫头','翻车'));
    Query OK, 0 rows affected (0.26 sec)

# 4. t7 表 ,hobby字段可多选, 并自带去重功能 
    mysql> insert into t7 values('lisi','抽烟,喝酒,喝酒,喝酒');
    # 查看t7表数据
    mysql> select * from t7;
    +------+---------------+
    | name | hobby         |
    +------+---------------+
    | lisi | 抽烟,喝酒     |
    +------+---------------+

    # 错误实例 ,爬山不在设定的hobby字段内.
    mysql> insert into t7 values('lisi','抽烟,喝酒,喝酒,喝酒,爬山');
    ERROR 1265 (01000): Data truncated for column 'hobby' at row 1

四丶mysql中的表的约束

约束种类:

# unsigned : 无符号 ,适用于数值型
# NOT NULL :非空约束,指定某列不能为空; 
# UNIQUE : 唯一约束,指定某列或者几列组合不能重复
# PRIMARY KEY :主键约束,指定该列的值可以唯一地标识该列记录
# FOREIGN KEY :外键约束,指定该行记录从属于主表中的一条记录,主要用于参照完整性
# default :   设置默认值
# auto_increment : 自增

Not null 非空约束:

      含义: 表示这个字段在增加时,不能为空

# 1. 创建表 t8 指定id字段不能为空
    mysql> create table t8(id int not null);
    Query OK, 0 rows affected (0.32 sec)
# 2. t8表 增加数据
    # 错误 1:
    mysql> insert into t8 values();
    ERROR 1364 (HY000): Field 'id' doesn't have a default value
    
    # 错误 2: 由于id字段设置了不为空,
    mysql> insert into t8 values(null);
    ERROR 1048 (23000): Column 'id' cannot be null
    
    # 必须填写数据,才能插入成功
    mysql> insert into t8 values(1);
    Query OK, 1 row affected (0.12 sec)
    # 查询表结果
    mysql> select * from t8;
    +----+
    | id |
    +----+
    |  1 |
    +----+
    1 row in set (0.00 sec)

      设置not null生效:严格模式

设置严格模式:
    不支持对not null字段插入null值
    不支持对自增长字段插入”值
    不支持text字段有默认值

直接在mysql中生效(重启失效):
mysql>set sql_mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION";

配置文件添加(永久失效):
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

DEFAULT 默认值约束:

      含义:

         我们约束某一列不为空,如果这一列中经常有重复的内容,就需要我们频繁的插入,这样会给我们的操作带来新的负担,于是就出现了默认值的概念。

         默认值,创建列时可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值

#1.  创建表 t9  设置id1 字段不为空, id2字段默认值222
    mysql> create table t13 (id1 int not null,id2 int not null default 222);

    #查看表结构
    mysql> desc t9;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | id1   | int(11) | NO   |     | NULL    |       |
    | id2   | int(11) | NO   |     | 222     |       |
    +-------+---------+------+-----+---------+-------+

# 2. t9表添加数据, 只向id1字段添加值,会发现id2字段会使用默认值填充
    mysql> insert into t9 (id1) values (111);

    mysql> select * from t13;
    +-----+-----+
    | id1 | id2 |
    +-----+-----+
    | 111 | 222 |
    +-----+-----+
# 3. t9表添加数据, id1字段不能为空,所以不能单独向id2字段填充值;
    mysql> insert into t13 (id2) values (223);
    ERROR 1364 (HY000): Field 'id1' doesn't have a default value

# 4. t9表添加数据, 向id1,id2中分别填充数据,id2的填充数据会覆盖默认值
    mysql> insert into t13 (id1,id2) values (112,223);

    mysql> select * from t13;
    +-----+-----+
    | id1 | id2 |
    +-----+-----+
    | 111 | 222 |
    | 112 | 223 |
    +-----+-----+

UNIQUE 唯一约束:

      含义:

​         唯一约束,指定某列或者几列组合不能重复

         不允许重复插入相同的值. 当值为null时,可以重复插入.

   UNIQUE案例:

# 方法一:
create table department1(
id int,
name varchar(20) unique,
comment varchar(100)
);


# 方法二:
create table department2(
id int,
name varchar(20),
comment varchar(100),
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'

   UNIQUE + NOT NULL = primary key

####  唯一约束 + 非空约束 = 主键约束

# 1. 创建表 t11 设置 非空+唯一 
mysql> create table t11(id int not null unique);
Query OK, 0 rows affected (0.02 sec)

# 2. 查看表结构
mysql> desc t11;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id    | int(11) | NO   | PRI | NULL    |       |
+-------+---------+------+-----+---------+-------+
row in set (0.00 sec)


​   联合唯一:

# 1 .创建service表, host和port 字段联合唯一
mysql>  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> desc service;
    +-------+-------------+------+-----+---------+----------------+
    | Field | Type        | Null | Key | Default | Extra          |
    +-------+-------------+------+-----+---------+----------------+
    | id    | int(11)     | NO   | PRI | NULL    | auto_increment |
    | name  | varchar(20) | YES  |     | NULL    |                |
    | host  | varchar(15) | NO   | MUL | NULL    |                |
    | port  | int(11)     | NO   |     | NULL    |                |
    +-------+-------------+------+-----+---------+----------------+
    
# 2 .插入数据
    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.12 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    # 查询结果
    mysql> select * from service;
    +----+---------+--------------+------+
    | id | name    | host         | port |
    +----+---------+--------------+------+
    |  1 | nginx   | 192.168.0.10 |   80 |
    |  2 | haproxy | 192.168.0.20 |   80 |
    |  3 | mysql   | 192.168.0.30 | 3306 |
    +----+---------+--------------+------+


# 3. 再次添加数据, port 和 host 已经存在相同的, 报错
    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 主键约束:

      含义:

         主键为了保证表中的每一条数据的该字段都是表格中的唯一值. 它是用来确定表中的每一行数据都是唯一的存在

         主键可以设置一个字段或多个字段,当主键包含多个栏位时,成为联合主键.

         设置主键时必须唯一 + 非空, 但至少设置主键非空unique.

      单字段主键:

# 1. 创建表 tb1 字段id 被约束成主键
    mysql> create table tb1(id int primary key);
    Query OK, 0 rows affected (0.33 sec)

# 2. 查看表tb1 结构
    mysql> desc tb1;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | id    | int(11) | NO   | PRI | NULL    |       |
    +-------+---------+------+-----+---------+-------+
    1 row in set (0.01 sec)

# 3.增加有值数据
    mysql> insert into tb1 values(1);
    Query OK, 1 row affected (0.04 sec)

# 4.增加null数据,报错. 不允许增加null数据
    mysql> insert into tb1 values(null);
    ERROR 1048 (23000): Column 'id' cannot be null


# 5. 创建一个没有主键约束的tb2表,
    mysql> create table tb2(id int);
    Query OK, 0 rows affected (0.34 sec)
    
    # 查看tb2表结构 ,可以看出 没有主键约束,存值时可以为空
    mysql> desc tb2;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | id    | int(11) | YES  |     | NULL    |       |
    +-------+---------+------+-----+---------+-------+
    
# 6. 对tb2表的id字段进行主键约束修改
    mysql> alter table tb2 modify id int primary key;
    Query OK, 0 rows affected (0.54 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    # 查看tb2表结构,不难发现 id字段被附上了主键约束,存值时不能为空
    mysql> desc tb2;
    +-------+---------+------+-----+---------+-------+
    | Field | Type    | Null | Key | Default | Extra |
    +-------+---------+------+-----+---------+-------+
    | id    | int(11) | NO   | PRI | NULL    |       |
    +-------+---------+------+-----+---------+-------+

      多字段主键:

# 1 . 创建表tb3 ip字段和port字段 设置成联合主键
    create table tb3(id int not null ,
                     name char(5),
                     ip char(15),
                     port int,
                     primary key(ip,port) # ip和port 字段设置成联合主键
                    );
                   
# 2. 查看表结构,不难发现 ip和port都具有了主键约束
    mysql> desc tb3;
    +-------+----------+------+-----+---------+-------+
    | Field | Type     | Null | Key | Default | Extra |
    +-------+----------+------+-----+---------+-------+
    | id    | int(11)  | NO   |     | NULL    |       |
    | name  | char(5)  | YES  |     | NULL    |       |
    | ip    | char(15) | NO   | PRI |         |       |
    | port  | int(11)  | NO   | PRI | 0       |       |
    +-------+----------+------+-----+---------+-------+

# 3.插入数据
    mysql> insert into tb3 values(1,'ftp','10.10.1.1',8848);
    Query OK, 1 row affected (0.12 sec)
    # 查看结果
    mysql> select * from tb3;
    +----+------+-----------+------+
    | id | name | ip        | port |
    +----+------+-----------+------+
    |  1 | ftp  | 10.10.1.1 | 8848 |
    +----+------+-----------+------+
    1 row in set (0.00 sec)
    
# 4. 插入相同的数据会报错,由于约束原因,只能存在一个ip和port
    mysql> insert into tb3 values(1,'ftp','10.10.1.1',8848);
    ERROR 1062 (23000): Duplicate entry '10.10.1.1-8848' for key 'PRIMARY'
    

# 5. 查看表tb3 的详细结构 show  create table tb3;
    mysql>  show  create table tb3;
    | tb3   | CREATE TABLE `tb3` (
      `id` int(11) NOT NULL,
      `name` char(5) DEFAULT NULL,
      `ip` char(15) NOT NULL DEFAULT '',
      `port` int(11) NOT NULL DEFAULT '0',
      PRIMARY KEY (`ip`,`port`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |


auto_increment 自增约束:

      含义:

​         约束字段为自动增长,被约束的字段必须同时被key约束

      特点:

         第一 只能操作数字

         第二 自带非空属性

​         第三 只能对unique字段进行设置

​         第四 不受删除影响的

自增约束:

# 1. 创建 tb4 id字段 自增约束, 至少是unique约束, 否则报错
    mysql> create table tb4(id int auto_increment);
    ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
    
# 2. 创建tb4 id字段 自增约束,
    mysql> create table tb4(id int unique auto_increment);
    Query OK, 0 rows affected (0.30 sec)
    # 查看表结构,不难发现id自动默认成了 主键约束
    mysql> desc tb4;
    +-------+---------+------+-----+---------+----------------+
    | Field | Type    | Null | Key | Default | Extra          |
    +-------+---------+------+-----+---------+----------------+
    | id    | int(11) | NO   | PRI | NULL    | auto_increment |
    +-------+---------+------+-----+---------+----------------+

# 3. 增加数据
    mysql> insert into tb4 values(1);
    Query OK, 1 row affected (0.12 sec)
    # 由于主键约束原因 ,重复添加一个值会 报错
    mysql> insert into tb4 values(1);
    ERROR 1062 (23000): Duplicate entry '1' for key 'id'
    
# 4. 不受删除影响,对于自增的字段,在用delete删除后,再插入值,该字段仍按照删除前的位置继续增长
    mysql> select * from tb4;
    +----+
    | id |
    +----+
    |  1 |
    |  2 |
    |  3 |
    +----+
   
    # 删除表中的数据
    mysql> delete from  tb4;
    Query OK, 3 rows affected (0.11 sec)
    
    # 再次查询
    mysql> select * from tb4;
    Empty set (0.00 sec)
    
    # 再次增加数据
    mysql> insert into tb4 values();
    Query OK, 1 row affected (0.11 sec)
    
    # 发现从4 开始
    mysql> select * from tb4;
    +----+
    | id |
    +----+
    |  4 |
    +----+
    1 row in set (0.00 sec)
    
    # 原因: delete 不会删除 id 自增字段的信息, 
        # show create table tb4;可以看出  AUTO_INCREMENT=5 是保留下一次存数据自增的值
    mysql> show create table tb4;
    | tb4   | CREATE TABLE `tb4` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      UNIQUE KEY `id` (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 |

# 5. truncate 清空, 则自增字段的值也被清空
    # 清空表
    mysql> truncate table tb4;
    Query OK, 0 rows affected (0.29 sec)
    
    # 可以看出 没有自增信息. 表示所有信息被清空了
    mysql> show create table tb4;
    | tb4   | CREATE TABL
    E `tb4` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      UNIQUE KEY `id` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

      offset偏移量:

​         #在创建完表后,修改自增字段的起始值

# 1. 创建表student  设置id字段主键 自增约束
create table student(
        id int primary key auto_increment,
        name varchar(20),
        sex enum('male','female') default 'male'
);

# 2. 修改 id 字段 自增量
    mysql> alter table student auto_increment=4;
    Query OK, 0 rows affected (0.12 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    # 查看表的详细信息 ,发现 自增了到了4: AUTO_INCREMENT=4
    mysql> show create table student;
    | student | CREATE TABLE `student` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) DEFAULT NULL,
      `sex` enum('male','female') DEFAULT 'male',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |

# 3. 增加值 ,的确是从指定偏移量继续增加
    mysql> insert into student(name) values('张三');
    Query OK, 1 row affected (0.11 sec)

    mysql> select * from student;
    +----+--------+------+
    | id | name   | sex  |
    +----+--------+------+
    |  4 | 张三   | male |
    +----+--------+------+
    
# 4. 创建表的时候可以设置 偏移量
    # 也可以创建表时指定auto_increment的初始值,注意初始值的设置为表选项,应该放到括号外
    create table student(
            id int primary key auto_increment,
            name varchar(20),
            sex enum('male','female') default 'male'
        )auto_increment=3;



############################################################################################

### 步长:auto_increment_increment,起始偏移量:auto_increment_offset

#设置步长
sqlserver:自增步长
    基于表级别
    create table t1(
        id int。。。
    )engine=innodb,auto_increment=2 步长=2 default charset=utf8

mysql自增的步长:
    show session variables like 'auto_inc%';
    
    #基于会话级别
    set session auth_increment_increment=2 #修改会话级别的步长

    #基于全局级别的
    set global auth_increment_increment=2 #修改全局级别的步长(所有会话都生效)


#!!!注意了注意了注意了!!!
If the value of auto_increment_offset is greater than that of auto_increment_increment, the value of auto_increment_offset is ignored. 
翻译:如果auto_increment_offset的值大于auto_increment_increment的值,则auto_increment_offset的值会被忽略 ,这相当于第一步步子就迈大了,扯着了蛋
比如:设置auto_increment_offset=3,auto_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     |
+--------------------------+-------+



create table student(
id int primary key auto_increment,
name varchar(20),
sex enum('male','female') default 'male'
);

mysql> insert into student(name) values('egon1'),('egon2'),('egon3');
mysql> select * from student;
+----+-------+------+
| id | name  | sex  |
+----+-------+------+
|  3 | egon1 | male |
|  8 | egon2 | male |
| 13 | egon3 | male |
+----+-------+------+


foreign key 外键约束:

      含义:

         外键的是使两种原本没有关系的表产生一定的联系. 由于在一张表存储的数据量过大,容易造成数据冗余和效率低下. 把一张表分成两张表,使用外键让其产生一定的关联性

      特点:

         对应外表中的字段至少是unique的,推荐使用主键作为关联字段

   外键案例:

      学生表字段: sid , sname姓名 , gender ,cid外键

      班级表字段: cid , cname班级名 ,

###  外键关联必须是主键,或者至少是唯一unique ###

# 1. 先创建没有外键的表 class
create table class(
    cid int primary key auto_increment, 
    cname char(6));

# 2. 再创建具有外键的表 student
create table student(
    sid int primary key auto_increment , 
    sname char(6) ,
    gender enum('男','女')  default '男',
    cid int ,
    # 固定语法,foreign key(当前表主键), references 关联表名(关联表主键)
    foreign key(sid) references class(cid) 
    );
    
 
 
# 3. 查看报表结构
    mysql> desc class;
    +-------+---------+------+-----+---------+----------------+
    | Field | Type    | Null | Key | Default | Extra          |
    +-------+---------+------+-----+---------+----------------+
    | cid   | int(11) | NO   | PRI | NULL    | auto_increment |
    | cname | char(6) | YES  |     | NULL    |                |
    +-------+---------+------+-----+---------+----------------+
    2 rows in set (0.01 sec)

    mysql> desc student;
    +--------+-------------------+------+-----+---------+----------------+
    | Field  | Type              | Null | Key | Default | Extra          |
    +--------+-------------------+------+-----+---------+----------------+
    | sid    | int(11)           | NO   | PRI | NULL    | auto_increment |
    | sname  | char(6)           | YES  |     | NULL    |                |
    | gender | enum('男','女')   | YES  |     | 男      |                |
    | cid    | int(11)           | YES  |     | NULL    |                |
    +--------+-------------------+------+-----+---------+----------------+
    4 rows in set (0.01 sec)

 
# 4. 添加数据 ,必须先添加没有外键关联的表,否则有外键关联的表因找不到主键而添加失败
    mysql> insert into student(sname,cid) values('李四',1);
    ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`day39`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`sid`) REFERENCES `class` (`cid`))
    
    
# 5. 先给class 表插入数据 , 再给student表插入数据(student表中关联的外键一定是存在的,否则报错)
    
    # class 表添加数据
    mysql> insert into class values(1,'高一一班');
    Query OK, 1 row affected (0.03 sec)
    # 查看 class 表
    mysql> select * from class;
    +-----+--------------+
    | cid | cname        |
    +-----+--------------+
    |   1 | 高一一班     |
    +-----+--------------+
    1 row in set (0.00 sec)
    
    # student 表添加数据
    mysql> insert into student values(1,'赵小','男',1);
    Query OK, 1 row affected (0.04 sec)
    # 查看student 表
    mysql> select  * from student;
    +-----+--------+--------+------+
    | sid | sname  | gender | cid  |
    +-----+--------+--------+------+
    |   1 | 赵小   | 男     |    1 |
    +-----+--------+--------+------+
    1 row in set (0.00 sec)
    
# 6. 删除或修改class表都是失败的,因为student表内还有数据和其关联,不能修改.
    # 只有删除student表内的所有和其关联的表才能修改或删除class表的数据
    mysql> delete from class where cid=1;
    ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`day39`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`sid`) REFERENCES `class` (`cid`))
    
    mysql> update class set cid=2 where cid=1;
    ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`day39`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`sid`) REFERENCES `class` (`cid`))

      级联删除on delete cascade 和级联更新 on update cascade:

### 由于外键的存在,不能随意对被关联表进行修改或删除. 
### 因此产生级联删除 和 级联修改 ,
### 级联删除一般不推荐使用,

# 1. 先创建没有外键的表 class1
create table class1(
    cid int primary key auto_increment, 
    cname char(6));

# 2. 再创建具有外键的表 student1
create table student1(
    sid int primary key auto_increment , 
    sname char(6) ,
    gender enum('男','女')  default '男',
    cid int ,
    # 固定语法,foreign key(当前表主键), references 关联表名(关联表主键)
    foreign key(sid) references class1(cid) on delete cascade on update cascade 
    );
  
# 3. 查看表结构和数据  
        mysql> desc class1;
        +-------+---------+------+-----+---------+----------------+
        | Field | Type    | Null | Key | Default | Extra          |
        +-------+---------+------+-----+---------+----------------+
        | cid   | int(11) | NO   | PRI | NULL    | auto_increment |
        | cname | char(6) | YES  |     | NULL    |                |
        +-------+---------+------+-----+---------+----------------+
        2 rows in set (0.01 sec)

        mysql> desc student1;
        +--------+-------------------+------+-----+---------+----------------+
        | Field  | Type              | Null | Key | Default | Extra          |
        +--------+-------------------+------+-----+---------+----------------+
        | sid    | int(11)           | NO   | PRI | NULL    | auto_increment |
        | sname  | char(6)           | YES  |     | NULL    |                |
        | gender | enum('男','女')   | YES  |     | 男      |                |
        | cid    | int(11)           | YES  |     | NULL    |                |
        +--------+-------------------+------+-----+---------+----------------+
        4 rows in set (0.01 sec)

        mysql> select * from class1;
        +-----+--------------+
        | cid | cname        |
        +-----+--------------+
        |   1 | 高一一班     |
        +-----+--------------+
        1 row in set (0.00 sec)

        mysql> select * from student1;
        +-----+--------+--------+------+
        | sid | sname  | gender | cid  |
        +-----+--------+--------+------+
        |   1 | 赵小   | 男     |    1 |
        +-----+--------+--------+------+
        1 row in set (0.00 sec)



### 级联更新  同步更新
    ## 更新前 两个表的信息
        mysql> select * from class1;
        +-----+--------------+
        | cid | cname        |
        +-----+--------------+
        |   1 | 高一一班     |
        +-----+--------------+
        1 row in set (0.00 sec)

        mysql> select * from student1;
        +-----+--------+--------+------+
        | sid | sname  | gender | cid  |
        +-----+--------+--------+------+
        |   1 | 赵小   | 男     |    1 |
        +-----+--------+--------+------+
        1 row in set (0.00 sec)
        
    # 级联更新
    mysql> update class1  set cid=2 where cid=1;
    Query OK, 1 row affected (0.04 sec)
    Rows matched: 1  Changed: 1  Warnings: 0
    
    # 更新后 两个表的数据同时被更新
        mysql> select * from class1;
        +-----+--------------+
        | cid | cname        |
        +-----+--------------+
        |   2 | 高一一班     |
        +-----+--------------+
        1 row in set (0.00 sec)

        mysql> select * from student1;
        +-----+--------+--------+------+
        | sid | sname  | gender | cid  |
        +-----+--------+--------+------+
        |   2 | 赵小   | 男     |    1 |
        +-----+--------+--------+------+
        1 row in set (0.00 sec)


### 级联删除,同步删除
    ## 删除前两个表的数据
        mysql> select * from class1;
        +-----+--------------+
        | cid | cname        |
        +-----+--------------+
        |   2 | 高一一班     |
        +-----+--------------+
        1 row in set (0.00 sec)

        mysql> select * from student1;
        +-----+--------+--------+------+
        | sid | sname  | gender | cid  |
        +-----+--------+--------+------+
        |   2 | 赵小   | 男     |    1 |
        +-----+--------+--------+------+
        1 row in set (0.00 sec)
      
      # 级联删除
      mysql> delete from class1 ;
      Query OK, 1 row affected (0.12 sec)
      
      # 删除后两个表的数据
            mysql> select * from class1;
            Empty set (0.00 sec)

            mysql> select * from student1;
            Empty set (0.00 sec)