MySQL之DDL表创建及DML数据处理操作

一:DDL创建数据库基本介绍

  存储数据是处理数据的第一步 。只有正确地把数据存储起来,我们才能进行有效的处理和分析。那么,怎样才能把用户各种经营相关的、纷繁复杂的数据,有序、高效地存储起来呢? 在MySQL中,一个完整的数据存储过程总共有 4 步,分别是创建数据库-->确认字段-->创建数据表-->插入数据。我们要先创建一个数据库,而不是直接创建数据表,因为从系统架构的层次上看,MySQL数据库系统从大到小依次是 数据库服务器、数据库、数据表 、数据表的行与列。 MySQL数据库服务器之前已经安装。所以,我们就从创建数据库开始。

1:标识符命名规则

①:数据库名、表名不得超过30个字符,变量名不得超过29个字符
②:必须只能包含 A–Z, a–z, 0–9, _ 共63个字符
③:数据库名、表名、字段名等对象名中间不得包含空格
④:同一个MySQL软件中,数据库不能同名;同一个库中,表不能重名;同一个表中,字段不能重名
⑤:必须保证你的字段没有和保留字、数据库系统或常用方法冲突。如果坚持使用,请在SQL语句中使用``(着重号)引起来
⑥:保持字段名和类型的一致性:在命名字段并为其指定数据类型的时候一定要保证一致性,
    假如数据类型在一个表里是整数,那在另一个表里可就别变成字符型了,这样可能造成问题,如外键的创建时类型不一样

2:MySQL中的数据类型

  MySQL中基本数据类型介绍

二:DDL创建和管理数据库

1:创建数据库

基础语法:CREATE DATABASE [IF NOT EXISTS] 数据库名字 [库选项]
    IF NOT EXISTS:代表如果数据库不存在则创建数据库,存在则不再执行此语句
    库选项:用来约束数据库,分为2个选项
        字符集设定:CHARSET/CHARACTER SET 指明这个库具体的字符集,常用GBK和UTF8
        校对集设定:COLLATE 指定具体的校队集(数据比较规则)
    注:不能使用系统关键字和保留字,如必须使用请加着重号
例:
    ①:创建数据库
        CREATE DATABASE `dbtest`
    ②:创建数据库并指定字符集和校对集
        CREATE DATABASE `dbtest` CHARACTER SET UTF8 COLLATE utf8_general_ci
    ③:判断数据库是否存在,不存在则创建数据库(推荐)
        CREATE DATABASE IF NOT EXISTS `dbtest` CHARACTER SET UTF8 COLLATE utf8_general_ci
执行示例的其中一个后:
    ①:在数据库系统(DBMS)中增加了相对于的库信息
    ②:会在MySQL数据文件夹下:Data目录下创建一个对应的数据库名文件夹
    ③:会在当前的文件夹下创建一个opt文件用来保存库选项

2:查询/使用数据库

# 以刚才创建的 dbtest 数据库为例
# 查询当前所有的数据库
    SHOW DATABASES;                     ## 有一个 S 代表多个数据库 
# 模糊查询数据库
  SHOW DATABASES LIKE 'pattern'     ## pattern为匹配模式 %或_(和SQL查询的like一样) # 查询当前正在使用的数据库
SELECT DATABASE(); ## 使用的是MySQL中的全局函数 # 查看指定库下的所有表 SHOW TABLES FROM dbtest; ## SHOW TABLES;查询的是当前库下的所有表 # 查看数据库创建信息 SHOW CREATE DATABASE dbtest; +----------+-----------------------------------------------------------------+ | Database | Create Database | +----------+-----------------------------------------------------------------+ | dbtest | CREATE DATABASE `dbtest` /*!40100 DEFAULT CHARACTER SET utf8 */ | +----------+-----------------------------------------------------------------+ SHOW CREATE DATABASE dbtest\G ## 竖直显示 *************************** 1. row *************************** Database: dbtest Create Database: CREATE DATABASE `dbtest` /*!40100 DEFAULT CHARACTER SET utf8 */ # 使用/切换数据库 USE 数据库名; 注意:要操作表格和数据之前必须先说明是对哪个数据库进行操作(就是先USE 数据库名), 否则就要对所有对象加上“数据库名.”。

3:修改数据库

①:修改数据库名字,但是不建议修改,以防保证数据问题,具体修改库名
    RENAME DATABASE 老数据库名称 TO 新数据库名称 
    注:这个语法在MySQL5.1.7中被添加进来,到了5.1.23又去掉了。据说有可能丢失数据。
    若真的要用或者有的数据库管理工具存在此功能,其实它是因为先把数据备份,创建新的数据库,再把数据复制进去
②:修改库选项的字符集和校对集,但是如果数据库里面有存在的表数据等等,不建议修改,,以防字符集不统一
基础语法:ALTER DATABASE 数据库名 [库选项]
    库选项:
        charset/character set[=] 字符集
        collate 校对集
示例:
    SHOW CREATE DATABASE dbtest;
        +----------+-----------------------------------------------------------------+
        | Database | Create Database                                                 |
        +----------+-----------------------------------------------------------------+
        | dbtest   | CREATE DATABASE `dbtest` /*!40100 DEFAULT CHARACTER SET utf8 */ |
        +----------+-----------------------------------------------------------------+
    修改字符集
    ALTER DATABASE dbtest CHARSET=GBK COLLATE gbk_chinese_ci;
    SHOW CREATE DATABASE dbtest;
        +----------+----------------------------------------------------------------+
        | Database | Create Database                                                |
        +----------+----------------------------------------------------------------+
        | dbtest   | CREATE DATABASE `dbtest` /*!40100 DEFAULT CHARACTER SET gbk */ |
        +----------+----------------------------------------------------------------+

4:删除数据库

基础语法:DROP DATABASE [ IF EXISTS ] 数据库名
方式1:删除指定的数据库,不存在则出现问题
    DROP DATABASE dbtest 
方式2:删除指定的数据库,不存在此数据库则跳过不执行
    DROP DATABASE IF EXISTS dbtest

三:DDL创建数据库表和管理表

1:创建数据库表(第一种 基本 方式)

基本语法:
    CREATE TABLE [IF NOT EXISTS] [数据库名.]表名(
        字段1, 数据类型 [约束条件] [默认值] [字段备注信息],
        字段1, 数据类型 [约束条件] [默认值] [字段备注信息],
        字段1, 数据类型 [约束条件] [默认值] [字段备注信息],
        ...
        [表约束条件]
    )[表字符集] [表校对集] [表存储引擎];
  注:【表字符集】【表校对集】【表存储引擎】统称表选项 参数介绍:
[IF NOT EXISTS]
    若当前数据库中不存在要创建的数据表,则创建数据表;反之存在要创建的数据表,则忽略不创建数据表
[表字符集]:charset/character set 具体字符集;保证表中数据存储的字符集 [表校对集]:collate 具体的校对集 [表存储引擎]:engine 具体存储引擎innodb和myisam 注:在创建数据表的时候必须指明当前的库使用 USE 库名,就是说在那个表下创建数据表 创建表举例(标准,可能有一些关键字不怎么熟悉,后面包括后面文章会介绍): CREATE TABLE IF NOT EXISTS dbtest.student( sid INT(4) PRIMARY KEY AUTO_INCREMENT COMMENT "主键ID", sname VARCHAR(6) NOT NULL COMMENT "姓名", ssex ENUM('','') DEFAULT '' COMMENT "性别", sage INT(4) COMMENT "年龄" )CHARACTER SET UTF8 COLLATE utf8_general_ci ENGINE INNODB; 创建表举例(基本方式,这种建表方式肯定不合规的,后面优化): CREATE TABLE IF NOT EXISTS dbtest.student( sid INT, sname VARCHAR(6), ssex ENUM('',''), sage TINYINT );

2:创建数据库表(第二种 子查询 方式)

基本语法:
    CREATE TABLE [IF NOT EXISTS] [数据库名.]表名 AS subquery;
介绍:
    此方式可以自定义选择子查询中的字段来创建table2后, 子查询中对应字段数据也一并转移至table2中
   注意:只是复制数据,而具体的约束是无法复制的 创建表举例:
CREATE TABLE IF NOT EXISTS dbtest.teacher AS SELECT tid,tname,tsex,tage,taddress FROM demo_school.teacher

3:创建数据库表(第三种 复制表结构 方式 )

基本语法:
    CREATE TABLE [IF NOT EXISTS] [数据库名.]表名1 LIKE [数据库名.]表名2;
介绍:
    此方式参照已有 表名2 的结构定义,来创建新的 表名1,不会将 表名2 中数据拿过来。
创建表举例:
    CREATE TABLE IF NOT EXISTS dbtest.teacher_new LIKE demo_school.teacher

4:查询数据库表及表结构

  在MySQL中创建好数据表之后,可以查看数据表的结构。MySQL支持使用 DESCRIBE / DESC 语句查看数据表结构,也支持使用 SHOW CREATE TABLE 语句查看数据表结构。使用SHOW CREATE TABLE语句不仅可以查看表创建时的详细语句,还可以查看存储引擎和字符编码。

①:查看创建的数据库表
    Ⅰ:查询当前库的所有表   SHOW TABLES;
        mysql> SHOW TABLES
        +------------------+
        | Tables_in_dbtest |
        +------------------+
        | student          |
        | teacher          |
        | teacher_new      |
        +------------------+
    Ⅱ:模糊查询当前库里的部分表 SHOW TABLE LIKE 'pattern';  -- 模糊查询%/_
        mysql> SHOW TABLES LIKE 'tea%';
        +-------------------------+
        | Tables_in_dbtest (tea%) |
        +-------------------------+
        | teacher                 |
        | teacher_new             |
        +-------------------------+
    Ⅲ:查询表的创建语句 SHOW CREATE TABLE [数据库名.]表名
        mysql> SHOW CREATE TABLE dbtest.student;
        +---------+-----------------------------------------------+
        | Table   | Create Table                                  |
        +---------+-----------------------------------------------+
        | student | CREATE TABLE `student` (
          `sid` int(4) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
          `sname` varchar(6) NOT NULL COMMENT '姓名',
          `ssex` enum('','') DEFAULT '' COMMENT '性别',
          `sage` tinyint(3) unsigned NOT NULL COMMENT '年龄',
          PRIMARY KEY (`sid`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8                      |
        +---------+-----------------------------------------------+
        注: '\g'也可以代表 ';' 分号 而 '\G' 则会把查询的数据样式进行一个改变
        mysql> SHOW CREATE TABLE dbtest.student\G
        *************************** 1. row ***************************
               Table: student
        Create Table: CREATE TABLE `student` (
          `sid` int(4) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
          `sname` varchar(6) NOT NULL COMMENT '姓名',
          `ssex` enum('','') DEFAULT '' COMMENT '性别',
          `sage` tinyint(3) unsigned NOT NULL COMMENT '年龄',
          PRIMARY KEY (`sid`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8

②:查看创建的数据库表结构的三种方式(下面三种方式一样)
    Ⅰ:DESC [数据库名.]表名     (推荐)
    Ⅱ:DESCRIBE [数据库名.]表名
    Ⅲ:SHOW COLUMNS FROM [数据库名.]表名
        mysql> DESCRIBE dbtest.student;
        +-------+---------------------+------+-----+---------+----------------+
        | Field | Type                | Null | Key | Default | Extra          |
        +-------+---------------------+------+-----+---------+----------------+
        | sid   | int(4)              | NO   | PRI | NULL    | auto_increment |
        | sname | varchar(6)          | NO   |     | NULL    |                |
        | ssex  | enum('男','女')      | YES  |     | 男      |                |
        | sage  | tinyint(3) unsigned | NO   |     | NULL    |                |
        +-------+---------------------+------+-----+---------+----------------+
    注:表结构字段说明:
        Field:字段名
        Type:列类型,字段类型,数据类型
        Null:列属性YES代表可为空,反之该列数据不可为空
        Key:索引:索引类型PRI主键或UNI唯一等等
        Default:列属性,默认值,不写默认NULL
        Extra:扩充额外的包括自增长写在里面

③:【补充】查询当前数据表状态:
  SHOW TABLE STATUS LIKE '表名'\G

其实我们创建完数据库表后我们可以到对应数据库文件下查看我们创建的表结构

存储引擎是myisam, 在data目录下会看到3类文件:.frm、.myi、.myd1*.frm--表定义,是描述表结构的文件。2*.MYD--"D"数据信息文件,是表的数据文件。3*.MYI--"I"索引信息文件,是表数据文件中任何索引的数据树
存储引擎是InnoDB, 在data目录下会看到2类文件:.frm、.ibd1*.frm--表结构的文件。2*.ibd--表数据和索引的文件。该表的索引(B+树)的每个非叶子节点存储索引,叶子节点存储索引和索引对应的数据。

补充说明INT设置显示宽度问题:MySQL在执行建表语句时,将我们student表中的sid字段的类型设置为int(4),这里的4实际上是int类型指定的显示宽度,默认的显示宽度为11。也可以在创建数据表的时候指定数据的显示宽度。不过在MySQL 8.x版本中,不再推荐为INT类型指定显示长度,并在未来的版本中可能去掉这样的语法。(具体的在后面的数据类型介绍有说明)

5:修改数据库表的表选项(字符集、校对集、存储引擎)

基本语法:
    ALTER TABLE [数据库名.]表名 表选项 [=]修改表选项【表字符集】【表校对集】【表存储引擎】:
  ALTER TABLE dbtest.studentCHARACTER SET gbk COLLATE gbk_chinese_ci ENGINE INNODB;
查询创建表信息:SHOW CREATE TABLE student\G
    截取最后一行:) ENGINE=InnoDB DEFAULT CHARSET=gbk

6:修改数据库表字段(增删改操作)

  注意:在使用 ALTER TABLE 进行表的基本修改操作时,在执行操作过程之前,应该确保对数据进行完整的备份 ,因为数据库的改变是无法撤销 的,如果添加了一个不需要的字段,可以将其删除;如果删除了一个需要的列,该列下面的所有数据都将会丢失。

基本语法:
Ⅰ:新增字段:
    ALTER TABLE [数据库名.]表名 ADD [COLUMN] 
        字段名 数据类型 [列属性] [字段备注信息] [FIRST|AFTER 位置]
Ⅱ:修改字段:
    ALTER TABLE [数据库名.]表名 MODIFY [COLUMN] 
        字段名1 数据类型 [列属性] [字段备注信息] [FIRST|AFTER 字段名2]
    说明:可以通过此种方式修改列的约束
Ⅲ:重命名字段:
    ALTER TABLE [数据库名.]表名 CHANGE [COLUMN] 
        旧名 新名 数据类型 [列属性] [字段备注信息] [FIRST|AFTER 位置]
Ⅳ:删除字段:
    ALTER TABLE [数据库名.]表名 DROP [COLUMN] 字段名
参数说明:
    FIRST:指明当前字段在表字段的最前面,设置FIRST则后面不需要跟具体字段
    AFTER:指明当前要操作的字段在哪个字段后面,默认在最后
举例说明: ①:为student表添加 address
VARCHAR(50) NOT NULL,并设置在ssex字段后面 ALTER TABLE dbtest.student ADD address VARCHAR(50) NOT NULL COMMENT "地址信息" AFTER ssex ②:修改student表的 address 字段的字符串长度为100,并且修改到 sage字段后面 ALTER TABLE dbtest.student MODIFY address VARCHAR(100) NOT NULL COMMENT "地址信息" AFTER sage ③:修改 address 字段名为 saddress ALTER TABLE dbtest.student CHANGE address saddress VARCHAR(100) NOT NULL COMMENT "地址信息" ④:删除字段 saddress ALTER TABLE dbtest.student DROP saddress;

7:重命名数据库表

基本语法:
Ⅰ:使用RENAME方式
    RENAME TABLE [数据库名.]旧表名 TO [数据库名.]新表名
Ⅱ:使用 ALTER 里的 RENAME 方式
    ALTER TABLE [数据库名.]旧表名 RENAME TO [数据库名.]新表名
基本示例:
     RENAME TABLE dbtest.student TO dbtest.student_new;

8:删除数据库表

  在MySQL中,当一张数据表没有与其他任何数据表形成关联关系时,可以将当前数据表直接删除。会执行以下步骤:数据和结构都被删除;所有正在运行的相关事务被提交;所有相关索引被删除。

  注意:操作将把表的定义和表中的数据一起删除,并且MySQL在执行删除操作时,不会有任何的确认信息提示,因此执行删除操时应当慎重。在删除表前,最好对表中的数据进行备份 ,这样当操作失误时可以对数据进行恢复,以免造成无法挽回的后果

基本语法:
    DROP TABLE [IF EXISTS] 数据表1 [, 数据表2, …, 数据表n];
        IF EXISTS含义:如果当前数据库中存在相应的数据表,则删除数据表;如果当前数据库中不存
                       在相应的数据表,则忽略删除语句,不再执行删除数据表的操作。
注:DROP TABLE语法一旦执行成功则不能回滚。

9:清空数据库表数据

TRUNCATE TABLE语句会执行以下步骤:删除表中所有的数据;释放表的存储空间
基本语法:
    TRUNCATE TABLE 数据表;
注:TRUNCATE语句不能回滚,而使用 DELETE 语句删除数据,可以回滚
补充事务的基本操作:

  # 事务自动提交设置为手动提交
    SET AUTOCOMMIT = FALSE
  # 事务提交操作
    COMMITTED
  # 事务回滚操作
    ROLLBACK

10:MySQL8新特性(DDL操作原子化)

  在MySQL8.0版本中,InnoDB表的DDL(数据库操作和数据库表操作)支持事务完整性,即DDL操作要么成功要么回滚。DDL操作回滚日志写入到data dictionary数据字典表mysql.innodb_ddl_log(该表是隐藏的表,通过show tables无法看到)中,用于回滚操作。通过设置参数,可将DDL操作日志打印输出到MySQL错误日志中。

举例:现在有一张demoA表
    MySQL5.7版本中执行:
        DROP TABLE demoA,demoB
        这时会报找不到demoB表,但是demoA表则已被删除
    MySQL8.0版本中执行:
        DROP TABLE demoA,demoB
        这时会报找不到demoB表,则回滚程序不会删除demoA表

11:MySQL8新特性(计算列)

  什么叫计算列呢?简单来说就是某一列的值是通过别的列计算得来的。例如,a列值为1、b列值为2,c列不需要手动插入,定义a+b的结果为c的值,那么c就是计算列,是通过别的列计算得来的。在MySQL 8.0中,CREATE TABLE 和 ALTER TABLE 中都支持增加计算列。

# 创建数据库表
CREATE TABLE IF NOT EXISTS db_test.employee (
    id INT ( 4 ) PRIMARY KEY AUTO_INCREMENT                         COMMENT '编号',
    name VARCHAR ( 5 ) NOT NULL                                    COMMENT '姓名',
    salary DECIMAL ( 6, 1 ) DEFAULT 0                               COMMENT '基本工资',
    bonus  DECIMAL ( 6, 1 ) DEFAULT 0                               COMMENT '员工奖金',
    sum_salary DECIMAL ( 6, 1 ) GENERATED ALWAYS AS (salary + bonus) VIRTUAL COMMENT '工资总和'
)CHARACTER SET UTF8 COLLATE utf8_general_ci ENGINE INNODB;
# 添加一条数据,执行完后,当前行的sum_salary字段的值为 salary+bonus的结果
INSERT INTO db_test.employee(name, salary, bonus) VALUES ('张三', 2000.0, 2500.0);

四:DML新增表数据和管理表数据

  在DML中对数据表里的数据进行操作时是可以使用事务来控制是否提交或者回滚操作

1:基本建表语句

# 创建数据库
CREATE DATABASE IF NOT EXISTS `db_test` CHARACTER SET UTF8 COLLATE utf8_general_ci
# 创建数据库表
CREATE TABLE IF NOT EXISTS db_test.teacher (
    tid INT ( 4 ) PRIMARY KEY AUTO_INCREMENT        COMMENT '编号',
    tname VARCHAR ( 5 ) NOT NULL                    COMMENT '姓名',
    tsex ENUM ( '男', '女' ) DEFAULT '男'            COMMENT '性别',
    tage TINYINT UNSIGNED                           COMMENT '年龄',
    tsalary DECIMAL ( 6, 1 ) DEFAULT 0              COMMENT '工资 最高99999.9',
    taddress VARCHAR ( 10 )                         COMMENT '住址' 
) CHARACTER SET UTF8 COLLATE utf8_general_ci ENGINE INNODB;

2:INSERT插入数据

Ⅰ:按照表的字段默认顺序插入一条数据
    语法:INSERT INTO [数据库名.]表名 VALUES (val1, val2...)
    注意:
        值列表中需要为表的每一个字段指定值,并且值的顺序必须和数据表中字段定义时的顺序相同
    示例:添加一条数据
        INSERT INTO db_test.teacher VALUES (1, '张三', '男', 23, 3500.00, '安徽六安');

Ⅱ:为表的指定字段插入一条数据
    语法:INSERT INTO [数据库名.]表名(col1,[col2, ... coln])  VALUES (val1, [val2, ... valn]);
    注意:
        为表的指定字段插入数据,就是在INSERT语句中只向部分字段中插入值,而其他字段的值为表定义时的默认值
        但在INSERT子句中随意列出列名,但是一旦列出,VALUES中要插入的value1,....valuen
        需要与column1,...columnn列一一对应。如果类型不同,将无法插入,并且MySQL会产生错误。
    示例:为表的指定字段添加一条数据(为指定tid字段,因为tid有主键自增长,后面介绍)
        INSERT INTO db_test.teacher(tname, tsex, tage, tsalary, taddress) 
            VALUES ('李四', '男', 22, 3000.00, '安徽合肥');

Ⅲ:同时插入多条记录
    语法①:INSERT INTO [数据库名.]表名 VALUES 
            (val1, [val2, ... valn]), (val1, [val2, ... valn]), ... (val1, [val2, ... valn]);
    语法②:INSERT INTO [数据库名.]表名(col1,[col2, ... coln]) VALUES 
            (val1, [val2, ... valn]), (val1, [val2, ... valn]), ... (val1, [val2, ... valn]);
    示例:为表的指定字段添加多条数据
        INSERT INTO db_test.teacher(tname, tsex, tage, tsalary, taddress) VALUES 
            ('王二', '男', 22, 3500.00, '安徽合肥'),('麻子', '男', 23, 3000.00, '安徽六安');
    说明:
        使用INSERT同时插入多条记录时,MySQL会返回一些在执行单行插入时没有的额外信息,这些信息的含义如下: 
        ①:Records:表明插入的记录条数。 
        ②:Duplicates:表明插入时被忽略的记录,原因可能是这些记录包含了重复的主键值。
        ③:Warnings:表明有问题的数据值,例如发生数据类型转换。
    注意:
        一个同时插入多行记录的INSERT语句等同于多个单行插入的INSERT语句,但是多行的INSERT语句在处理
        过程中效率更高 。因为MySQL执行单条INSERT语句插入多行数据比使用多条INSERT语句快,所以在插入
        多条记录时最好选择使用单条INSERT语句的方式插入。

Ⅳ:将查询结果插入到表中
    INSERT还可以将SELECT语句查询的结果插入到表中,此时不需要把每一条记录的值一个一个输入,只需
要使用一条INSERT语句和一条SELECT语句组成的组合语句即可快速地从一个或多个表中向一个表中插入多行。
    语法:INSERT INTO [数据库名.]目标表名 (col1,[col2, ... coln])
            SELECT (col1 [, col2, ... coln]) FROM 源表名 [WHERE条件]
    示例:在demo_school数据库里的teacher表中查询tid为1和2的数据插入
        INSERT INTO db_test.teacher(tname, tsex, tage, tsalary, taddress)
        SELECT tname, tsex, tage, tsalary, taddress FROM demo_school.teacher WHERE tid IN(1,2)
    注意:
        ①:在 INSERT 语句中加入子查询。
        ②:不必书写 VALUES 子句。
        ③:子查询中的值列表应与 INSERT 子句中的列名对应。
提示:
    ①:VALUES 也可以写成 VALUE ,但是VALUES是标准写法。
    ②:字符和日期型数据应包含在单引号中。

3:UPDATE更新数据 / DELETE删除数据

更新基本语法:
  UPDATE [数据库名.]表名 SET 字段名1=修改值1, 字段名2=修改值2 [WHERE条件]
示例:更新tid为3数据,tname="王彦" 和 tage = 28
    UPDATE db_test.teacher SET tname="王彦" , tage = 28 WHERE tid = 3

删除基本语法:
  DELETE FROM [数据库名.]表名 [WHERE条件]
示例:删除tid为5,6的数据
    DELETE FROM db_test.teacher WHERE tid IN(5, 6)

提示:更新删除建议添加 WHERE 条件,以免删除或更新全部数据造成损失

五:补充校对集问题(具体参考)

  校对集是用来数据比较的,其实我们一般不设置校对集的话,对于数据的排序是不区分大小写的,如果是数据区分大小写排序的话在创建库或创建表的时候就明确校对集

校对集的3种格式
    _bin(binary):取出二进制一位一位比较,区分大小写
    _cs(case sensitive):大小写敏感,区分大小写
    _ci(case insensitice):大小写不敏感,不区分大小写
注:大部分默认的都是_ci的比较模式
==》模糊查询支持的校对集:SHOW COLLATION LIKE '%utf8_ge%';
==》查询支持的校对集:SHOW COLLATION;
    (这里我就显示部分常用的校对集)
    +--------------------------+----------+-----+---------+----------+---------+
    | Collation                | Charset  | Id  | Default | Compiled | Sortlen |
    +--------------------------+----------+-----+---------+----------+---------+
    | gb2312_chinese_ci        | gb2312   |  24 | Yes     | Yes      |       1 |
    | gb2312_bin               | gb2312   |  86 |         | Yes      |       1 |
    | gbk_chinese_ci           | gbk      |  28 | Yes     | Yes      |       1 |
    | gbk_bin                  | gbk      |  87 |         | Yes      |       1 |
    | utf8_general_ci          | utf8     |  33 | Yes     | Yes      |       1 |
    | utf8_bin                 | utf8     |  83 |         | Yes      |       1 |
    | latin7_estonian_cs       | latin7   |  20 |         | Yes      |       1 |
    | latin7_general_ci        | latin7   |  41 | Yes     | Yes      |       1 |
    | latin7_bin               | latin7   |  79 |         | Yes      |       1 |
    | utf8mb4_general_ci       | utf8mb4  |  45 | Yes     | Yes      |       1 |
    | utf8mb4_bin              | utf8mb4  |  46 |         | Yes      |       1 |
    | ...                      | ...      |  ...| ...     | ...      |     ... |
    +--------------------------+----------+-----+---------+----------+---------+
  222 rows in set (0.00 sec)    
注:我在MySQL5.7版本中查询出222条校对集,这根据不同的数据库版本会有不同条数的校对集
注:Default代表默认的校对集,若设置数据库表为utf8mb4字符集,那么它默认校对集为utf8mb4_general_ci
创建校对集为 utf8mb4_bin 的数据库表:
    CREATE TABLE IF NOT EXISTS db_test.test_bin(
        `name` varchar(10) DEFAULT NULL
    ) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin ENGINE INNODB;

创建校对集为 utf8mb4_general_ci 的数据库表:
    CREATE TABLE IF NOT EXISTS db_test.test_ci(
        `name` varchar(10) DEFAULT NULL
    ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci ENGINE INNODB;

插入数据:
    INSERT INTO db_test.test_bin VALUES('a'),('A'),('b'),('B'),('c'),('C');
    INSERT INTO db_test.test_ci VALUES('a'),('A'),('b'),('B'),('c'),('C');
查询数据:
    SELECT * FROM db_test.test_bin ORDER BY `name`;
        -- 查询顺序:A B C a b c
    SELECT * FROM db_test.test_ci ORDER BY `name`;
        -- 查询顺序:a A b B c C
校对集问题演示说明

六:MySQL约束

1:约束的概述

  数据完整性(Data Integrity)是指数据的精确性(Accuracy)和可靠性(Reliability)。它是防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而提出的。

为了保证数据的完整性,SQL规范以约束的方式对表数据进行额外的条件限制
Ⅰ:从以下四个方面考虑:
    ①:实体完整性(Entity Integrity) :例如,同一个表中,不能存在两条完全相同无法区分的记录
    ②:域完整性(Domain Integrity) :例如:年龄范围0-120,性别范围“男/女”
    ③:引用完整性(Referential Integrity) :例如:员工所在部门,在部门表中要能找到这个部门
    ④:用户自定义完整性(User-defined Integrity) :例如:用户名唯一、密码不能为空等,本部门经理的工资不得高于
     本部门职工的平均工资的5倍。 Ⅱ:约束的作用范围(可从两种方式): 列级约束:将此约束声明在对应字段的后面 表级约束:在表中所有字段都声明完后,在所有字段的后而声明的约束
   注:约束可以为单列约束,也可以多个字段组成的多列约束 Ⅲ:约束分类(后面依次介绍) ①:
NOT NULL --> 非空约束(非空约束,规定某个字段不能为空) ②:UNIQUE --> 唯一性约束(唯一约束,规定某个字段在整个表中是唯一的,但可以为NULL) ③:PRIMARY KEY --> 主键约束(值唯一,并且不可为空) ④:FOREIGN KEY --> 外键约束(保证引用完整) ⑤:CHECK --> 检查约束(保证添加的数据在指定范围,MySQL8.0+功能) ⑥:DEFAULT --> 默认值约束 Ⅳ:查看指定表上的约束 #information_schema数据库名(系统库) #table_constraints表名称(专门存储各个表的约束) SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称';
关于DESC查询表中Key字段介绍:
    ①:如果Key是空的, 那么该列值的可以重复, 表示该列没有索引, 或者是一个非唯一的复合索引的非第一列
    ②:如果键是PRI,则列是主键或多列主键中的列之一
    ③:如果键是UNI,则该列是唯一索引的第一列;唯一索引允许多个空值,但可以通过检查Null字段来判断该列是否允许空
    ④:如果键为MUL,则该列是非唯一索引的第一列,其中允许在列中多次出现重复值

2:非空约束(NOT NULL)

  就是限制指定的字段下不可以添加空值(NULL)

关键字:NOT NULL
特点:
    ①:[默认]所有的类型的值都可以是NULL,包括INT、FLOAT等数据类型
    ②:非空约束只能出现在表对象的列上,只能某个列单独限定非空,不能组合非空
    ③:一个表可以有多个列都分别设置了非空
    ④:空字符串''不等于NULL,0也不等于NULL

建表时设置非空约束:
CREATE TABLE IF NOT EXISTS 表名称(
        字段1  数据类型                COMMENT '未指定非空约束NOT NULL',
        字段2  数据类型     NOT NULL   COMMENT '指定非空约束NOT NULL')
建表后设置非空约束(就是表字段的更新):
    注:我们要删除就直接使用下面语法把 NOT NULL 剔除就等于删除
    ALTER TABLE 表名 MODIFY 表字段 数据类型 NOT NULL

示例语句:
CREATE TABLE IF NOT EXISTS teacher(
        tid      INT              NOT NULL    COMMENT '老师ID',
        tname    VARCHAR(10)      NOT NULL    COMMENT '老师姓名',
        tsalary  DECIMAL(10,2)                COMMENT '老师工资')

3:唯一性约束(UNIQUE)

  就是限定指定字段列值不可以存在重复的数据,但是NULL数据除外(因为它不参与比较)

关键字:UNIQUE
特点:
    ①:同一个表可以有多个唯一约束。
    ②:唯一约束可以是某一个列的值唯一,也可以多个列组合的值唯一。
    ③:唯一性约束允许列值为空。
    ④:在创建唯一约束的时候,如果不给唯一约束命名,就默认和列名相同。
    ⑤:MySQL会给唯一约束的列上默认创建一个唯一索引。

建表时指定唯一约束:
    CREATE TABLE IF NOT EXISTS 表名称(
        字段1  数据类型              COMMENT '字段1未设置唯一约束',
        字段2  数据类型  UNIQUE      COMMENT '字段2设置唯一约束',
        字段3  数据类型  UNIQUE KEY  COMMENT '字段3设置唯一约束',
        字段4  数据类型              COMMENT '字段4未设置唯一约束',
        字段5  数据类型              COMMENT '字段5未设置唯一约束',
        -- 使用表级约束语法
        [CONSTRAINT 约束名称] UNIQUE KEY(字段名)        COMMENT '设置指定字段名称设置唯一约束',
        [CONSTRAINT 约束名称] UNIQUE KEY(字段4,字段5)    COMMENT '设置字段4和字段5为复合唯一索引')
单列唯一约束示例:
    -- 创建一个表并都指定唯一约束(id使用表级约束语法设置;name,email则使用列级约束设置
    CREATE TABLE IF NOT EXISTS demo_unique1(
        id      INT                COMMENT 'id字段',
        name    VARCHAR(10)    UNIQUE      COMMENT '姓名',
        email   VARCHAR(50)    UNIQUE KEY   COMMENT '邮箱',
        CONSTRAINT demo_unique_id    UNIQUE KEY(id));    
    -- 查询约束创建情况
    SELECT * FROM information_schema.table_constraints WHERE table_name = 'demo_unique1';
    +------------------+-----------------+---------------+------------+------------+---------------+
    |CONSTRAINT_CATALOG|CONSTRAINT_SCHEMA|CONSTRAINT_NAME|TABLE_SCHEMA|TABLE_NAME  |CONSTRAINT_TYPE|
    +------------------+-----------------+---------------+------------+------------+---------------+
    |def               |testys           |name           |testys      |demo_unique1|UNIQUE         |
    |def               |testys           |email          |testys      |demo_unique1|UNIQUE         |
    |def               |testys           |demo_unique_id |testys      |demo_unique1|UNIQUE         |
    +------------------+-----------------+---------------+------------+------------+---------------+
  -- 注:可以使用 DESC demo_unique1 来查看Key列里面的UNI,当出现UNI则可能是单列唯一约束,也可能是多列唯一约束
多列唯一约束示例:
    -- 创建一个表并都指定唯一约束(name,card使用表级约束语法设置)
    CREATE TABLE IF NOT EXISTS demo_unique2(
        name    VARCHAR(10)   COMMENT '姓名',
        card    VARCHAR(18)   COMMENT '身份证信息',
        CONSTRAINT demo_unique_nc UNIQUE KEY(name,card));
    -- 查询约束创建情况
    SELECT * FROM information_schema.table_constraints WHERE table_name = 'demo_unique2';
    +------------------+-----------------+---------------+------------+------------+---------------+
    |CONSTRAINT_CATALOG|CONSTRAINT_SCHEMA|CONSTRAINT_NAME|TABLE_SCHEMA|TABLE_NAME  |CONSTRAINT_TYPE|
    +------------------+-----------------+---------------+------------+------------+---------------+
    |def               |testys           |demo_unique_nc |testys      |demo_unique2|UNIQUE         |
    +------------------+-----------------+---------------+------------+------------+---------------+
说明:唯一单列约束在插入数据时可以插入多条NULL数据,但是数据不可以重复;
    唯一多列约束在插入数据时可以插入组合列为NULL,但是当组合列里面都存在数据时则不可以重复,
注意:可以插入      
    INSERT INTO demo_unique2 VALUES('张三','123'),('张三',NULL),('张三',NULL),(NULL,'123'),(NULL,'123');
注意:不可再次插入
    INSERT INTO demo_unique2 VALUES('张三','123');
    报错信息:ERROR 1062 (23000): Duplicate entry '张三-123' for key 'demo_unique_nc'
        
删除唯一约束:
    ①:添加唯一性约束的列上也会自动创建唯一索引。
    ②:删除唯一约束只能通过删除唯一索引的方式删除。(DROP INDEX)
    ③:删除时需要指定唯一索引名,唯一索引名就和唯一约束名一样。
    ④:如果创建唯一约束时未指定名称,如果是单列,就默认和列名相同;如果是组合列,
       那么默认和括号内排在第一个的列名相同。也可以自定义唯一性约束名
-- 删除demo_unique1表中约束名为`name`的唯一约束
    ALTER TABLE demo_unique1 DROP INDEX `name`
-- 使用创建表后的更新方式设置唯一约束
    ALTER TABLE demo_unique1 MODIFY `name` VARCHAR(10) UNIQUE KEY
    ALTER TABLE demo_unique1 ADD CONSTRAINT name_unique UNIQUE KEY(`name`);

注意:因为唯一约束创建后会字段创建唯一索引,所以可以通过 SHOW INDEX FROM 表名称; 查看表的索引

4:主键约束(PRIMARY KEY)

  主要就是标识表中的一行记录是唯一的

关键字:PRIMARY KEY
特点:
    ①:主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现NULL值。
    ②:一个表最多只能有一个主键约束,建立主键约束可以在列级别创建,也可以在表级别上创建。
    ③:主键约束对应着表中的一列或者多列(复合主键)。
    ④:如果是多列组合的复合主键约束,那么这些列都不允许为空值,并且组合的值不允许重复。
    ⑤:MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也被自动置为PRIMARY。
    ⑥:当创建主键约束时,系统默认会在所在的列或列组合上建立对应的主键索引
        (能够根据主键查询的,就根据主键查询,效率更高)
        如果删除主键约束了,主键约束对应的索引就自动删除了。(不推荐)
    ⑦:不要修改主键字段的值。因为主键是数据记录的唯一标识,如果修改了主键的值,就有可能会破坏数据的完整性。

建表时指定主键约束(注:使用表级方式设置名称是无效的)
    -- 使用列级模式设置字段1为主键
    CREATE TABLE IF NOT EXISTS 表名称(
        字段1  数据类型  PRIMARY KEY     COMMENT '字段1设置主键约束',
        字段2  数据类型                  COMMENT '字段2')
    -- 使用表级模式设置字段1为主键
    CREATE TABLE IF NOT EXISTS 表名称(
        字段1  数据类型        COMMENT '字段1',
        PRIMARY KEY(字段1)    COMMENT '设置字段1为主键约束')        
    -- 使用表级模式设置字段1和字段2为组合主键
    CREATE TABLE IF NOT EXISTS 表名称(
        字段1  数据类型                  COMMENT '字段1',
        字段2  数据类型                  COMMENT '字段2',
        PRIMARY KEY(字段1,字段2)    COMMENT '设置字段1和字段2为复合唯一索引')    
举例示例:
    -- 使用列级模式设置id为主键
    CREATE TABLE IF NOT EXISTS demo_primary1(
        `id`    INT PRIMARY KEY        COMMENT 'ID,指定主键',
        `name`  VARCHAR(18)            COMMENT '姓名');
    -- 使用表级模式设置id为主键
    CREATE TABLE IF NOT EXISTS demo_primary2(
        `id`    INT         COMMENT 'ID',
        `name`  VARCHAR(18)    COMMENT '姓名',
         PRIMARY KEY(id));
    -- 使用表级模式设置name和card为组合主键    
    CREATE TABLE IF NOT EXISTS demo_primary3(
        name  VARCHAR(10)    COMMENT '姓名',
        card  VARCHAR(18)    COMMENT '身份证信息',
        PRIMARY KEY(`name`,`card`));
    -- 组合主键插入数据注意事项:
    MySQL5.7下:
        INSERT INTO demo_primary3 VALUES('张三','123'),('张三',NULL);
        Records: 2  Duplicates: 0  Warnings: 1
        一条警告,虽然插入了,但是把空默认置为空字符串''
    MySQL8.0下:
        INSERT INTO demo_primary3 VALUES('张三','123'),('张三',NULL);
        ERROR 1048 (23000): Column 'card' cannot be null
        插入失败;card字段不可为NULL

查询主键约束设置情况(因为主键只能设置一次,所以查询哪个表都是一样的):
    SELECT * FROM information_schema.table_constraints WHERE table_name = 'demo_primary3';
    +------------------+-----------------+---------------+------------+-------------+---------------+
    |CONSTRAINT_CATALOG|CONSTRAINT_SCHEMA|CONSTRAINT_NAME|TABLE_SCHEMA|TABLE_NAME   |CONSTRAINT_TYPE|
    +------------------+-----------------+---------------+------------+-------------+---------------+
    |def               |testys           |PRIMARY        |testys      |demo_primary3|PRIMARY KEY    |
    +------------------+-----------------+---------------+------------+-------------+---------------+
查询表结构:(注:在Key列标注 PRI 则为主键,若一个Key列存在多个PRI,那么这表是组合主键)
    DESC demo_primary2;
    +-------+-------------+------+-----+---------+-------+
    | Field | Type        | Null | Key | Default | Extra |
    +-------+-------------+------+-----+---------+-------+
    | id    | int(11)     | NO   | PRI | NULL    |       |
    | name  | varchar(18) | YES  |     | NULL    |       |
    +-------+-------------+------+-----+---------+-------+

删除主键约束:
    -- 删除demo_primary1主键约束
    ALTER TABLE demo_primary1 DROP PRIMARY KEY
    -- 使用创建表后的更新方式设置主键约束
    ALTER TABLE demo_primary1 MODIFY id INT PRIMARY KEY
    ALTER TABLE demo_primary1 ADD PRIMARY KEY(id);
说明:删除主键约束,不需要指定主键名,因为一个表只有一个主键,删除主键约束后,非空还存在。

5:自增列(AUTO_INCREMENT)

  其实自增长就是对某个字段依次累加,如1,2,3...这种,不会存在重复

关键字:AUTO_INCREMENT
特点:
    ①:一个表最多只能有一个自增长列
    ②:当需要产生唯一标识符或顺序值时,可设置自增长
    ③:自增长只能设置在主键列或唯一键列上
    ④:自增约束的列的数据类型必须是整数类型
    ⑤:如果自增列指定了0和null,会在当前最大值的基础上自增;如果自增列手动指定了具体值,直接赋值为具体值。
    -- 注:推荐在主键后面设置自增,PRIMARY KEY AUTO_INCREMENT

建表时指定自增约束:
    -- 在主键约束上指定自增
    CREATE TABLE IF NOT EXISTS demo_auto1(
        id       INT       PRIMARY KEY AUTO_INCREMENT    COMMENT '主键ID自增长',
        name     VARCHAR(10)                            COMMENT '姓名');
    -- 在唯一约束上指定自增
    CREATE TABLE IF NOT EXISTS demo_auto2(
        id       INT     PRIMARY KEY                  COMMENT '主键ID',
        card     INT     UNIQUE KEY AUTO_INCREMENT    COMMENT '卡号自增长');
查询创建表的结构
    DESC demo_auto1;
    +-------+-------------+------+-----+---------+----------------+
    | Field | Type        | Null | Key | Default | Extra          |
    +-------+-------------+------+-----+---------+----------------+
    | id    | int(11)     | NO   | PRI | NULL    | auto_increment |
    | name  | varchar(10) | YES  |     | NULL    |                |
    +-------+-------------+------+-----+---------+----------------+
    DESC demo_auto2;
    +-------+---------+------+-----+---------+----------------+
    | Field | Type    | Null | Key | Default | Extra          |
    +-------+---------+------+-----+---------+----------------+
    | id    | int(11) | NO   | PRI | NULL    |                |
    | card  | int(11) | NO   | UNI | NULL    | auto_increment |
    +-------+---------+------+-----+---------+----------------+
其实我们可以在建表后再指定自增长
    语法:ALTER TABLE 表名称 MODIFY 字段名 数据类型 AUTO_INCREMENT;
删除自增长(剔除AUTO_INCREMENT):
    对有自增长的列执行:ALTER TABLE 表名称 MODIFY 字段名 数据类型; 
指定自增长从指定数开始地址(可以重置自增长为0)
  语法:ALTER TABLE 表名 AUTO_INCREMENT = 指定当前要从哪个数递增; 针对demo_auto1测试:
-- 自己手动插入4条数据 INSERT INTO demo_auto1 VALUES(1,'张三'),(2,'李四'),(3,'王五'),(6,'麻子'); -- 因为是自增ID,所以我没必要指定ID INSERT INTO demo_auto1 (`name`) VALUES('小武'),('大壮'); -- 这时小武ID为7,大壮ID为8 -- 删除ID为7,8的数据 DELETE FROM demo_auto1 WHERE id in(7,8) -- 这时候最大的ID为6号,按照下次插入时ID从7开始 -- 再次插入2条数据 INSERT INTO demo_auto1 (`name`) VALUES('小武'),('大壮'); -- 这时小武ID为9,大壮ID为10 为什么会出现这种情况? 在MySQL 8.0之前,自增主键AUTO_INCREMENT插入数据后会自动计算max(primary key)+1,在MySQL重启后,会重 置AUTO_INCREMENT=max(primary key)+1,这种现象在某些情况下会导致业务主键冲突或者其它难以发现的问题。 在MySQL 5.7系统中,对于自增主键的分配规则,是由InnoDB数据字典内部一个 计数器 来决定的,而该计数器只在 内存中维护 ,并不会持久化到磁盘中。当数据库重启时,该计数器会被初始化 MySQL 8.0将自增主键的计数器持久化到 重做日志 中。每次计数器发生改变,都会将其写入重做日志中。 如果数据库重启,InnoDB会根据重做日志中的信息来初始化计数器的内存值。

6:外键约束(FOREIGN KEY)

  主要就是限制某个表的某个字段的完整性,保证主表中某个字段在从表是存在的;假设一个辅导员有多个学生,这时学生表中对应的辅导员信息在辅导员表里必须有对应的部分。

关键字:FOREIGN KEY
主表和从表/父表和子表关系
    主表(父表):被引用的表,被参考的表;有个从表引用主表中的某个字段
    从表(子表):引用别人的表,参考别人的表;从表的某个字段引用了父表的字段
    示例:假设现在有个teacher老师表和一个student学生表,老师和学生假设是一对多关系,一个老师教多个学生
    示例:这时老师teacher是主表,学生student是从表,那么从表里某个外键列字段引用主表的主键或者唯一键字段

特点:
    ①:从表的外键列,必须引用或参考主表的主键或唯一约束的列;因为被依赖/被参考的值必须是唯一的
    ②:在创建外键约束时,如果不给外键约束命名,默认名不是列名,而是自动产生一个外键名,也可以指定外键约束名。
    ③:创建(CREATE)表时就指定外键约束的话,先创建主表,再创建从表
    ④:删表时,先删从表(或先删除外键约束),再删除主表
    ⑤:当主表的记录被从表参照时,主表的记录将不允许删除,如果要删除数据,需要先删除从表中依赖该记录的数据,
        然后才可以删除主表的数据
    ⑥:在"从表"中指定外键约束,并且一个表可以建立多个外键约束
    ⑦:从表的外键列与主表被参照的列名字可以不相同,但是数据类型必须一样,逻辑意义一致。如果类型不一样,
        创建子表时,就会出现错误 ERROR 1005 (HY000): Can't create table'database.tablename'(errno: 150)
    ⑧:当创建外键约束时,系统默认会在所在的列上建立对应的普通索引。但是索引名是外键的约束名。(根据外键查询效率很高)
    ⑨:删除外键约束后,必须 手动 删除对应的索引

添加外键约束:
CREATE TABLE IF NOT EXISTS 主表名称(
        字段1    数据类型 PRIMARY KEY,
        字段2    数据类型 );
    CREATE TABLE IF NOT EXISTS 从表名称(
        字段1    数据类型 PRIMARY KEY,
        字段2    数据类型 ,
        [CONSTRAINT <外键约束名称>] FOREIGN KEY(从表的某个字段) references 主表名(被参考字段));
    #(从表的某个字段)的数据类型必须与主表名(被参考字段)的数据类型一致,逻辑意义也一样
    #(从表的某个字段)的字段名可以与主表名(被参考字段)的字段名一样,也可以不一样
    -- FOREIGN KEY: 在表级指定子表中的列
    -- REFERENCES: 标示在父表中的列    
    注:外键只能在从表中创建

基本示例:
    -- 创建teacher为主表
    CREATE TABLE IF NOT EXISTS teacher(
        tid   INT  PRIMARY KEY COMMENT '老师ID',
        tname VARCHAR(10) COMMENT '老师姓名');
    -- 创建student为从表
    CREATE TABLE IF NOT EXISTS student(
        sid   INT  PRIMARY KEY COMMENT '学生ID',
        sname VARCHAR(10) COMMENT '学生姓名',
        tid INT        COMMENT '引用老师主键的外键字段',
        -- 创建外键
        CONSTRAINT stu_foreign_tid FOREIGN KEY(tid) references teacher(tid));
    -- 查询创建的表结构
        DESC teacher;
        +-------+-------------+------+-----+---------+-------+
        | Field | Type        | Null | Key | Default | Extra |
        +-------+-------------+------+-----+---------+-------+
        | tid   | int(11)     | NO   | PRI | NULL    |       |
        | tname | varchar(10) | YES  |     | NULL    |       |
        +-------+-------------+------+-----+---------+-------+
        DESC student;
        +-------+-------------+------+-----+---------+-------+
        | Field | Type        | Null | Key | Default | Extra |
        +-------+-------------+------+-----+---------+-------+
        | sid   | int(11)     | NO   | PRI | NULL    |       |
        | sname | varchar(10) | YES  |     | NULL    |       |
        | tid   | int(11)     | YES  | MUL | NULL    |       |
        +-------+-------------+------+-----+---------+-------+
    -- 查询外键创建情况
        SELECT * FROM information_schema.table_constraints WHERE table_name = 'student';
        +------------------+-----------------+---------------+------------+----------+---------------+
        |CONSTRAINT_CATALOG|CONSTRAINT_SCHEMA|CONSTRAINT_NAME|TABLE_SCHEMA|TABLE_NAME|CONSTRAINT_TYPE|
        +------------------+-----------------+---------------+------------+----------+---------------+
        |def               |testys           |PRIMARY        |testys      |student   |PRIMARY KEY    |
        |def               |testys           |stu_foreign_tid|testys      |student   |FOREIGN KEY    |
        +------------------+-----------------+---------------+------------+----------+---------------+
    -- 可以看出student中创建外键后使用DESC查看时tid字段的Key列被置为了MUL(非唯一索引)

总结:约束关系是针对双方的
    添加了外键约束后,主表的修改和删除数据受约束(因为从表引用了主表信息)
    添加了外键约束后,从表的添加和修改数据受约束(因为主表的信息需要在从表体现)
    在从表上建立外键,要求主表必须存在
    删除主表时,要求从表从表先删除,或将从表中外键引用该主表的关系先删除

约束等级(级联操作,重要):
    Cascade方式:    在父表上update/delete记录时,同步update/delete掉子表的匹配记录
    Set null方式:   在父表上update/delete记录时,将子表上匹配记录的列设为null,
                    但是要注意子表的外键列不能为NOT NULL
    No action方式:  如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
    Restrict方式:   同no action,都是立即检查外键约束
    Set default方式:父表有变更时,子表将外键列设置成一个默认的值,但Innodb不能识别

在使用外键的时候基本上都会使用到级联操作;最好的方式是级联操作是更新时从表更新,删除时子表信息置为NULL
比如:teacher上某个ID为1000更新ID为1001的老师,则从表student上对应引用老师ID为1000的则自动更新1001
比如:teacher上删除ID为1001的老师,则从表上引用老师ID1001的学生中的外键信息置为NUll
    CREATE TABLE IF NOT EXISTS teacher(
        tid   INT  PRIMARY KEY COMMENT '老师ID',
        tname VARCHAR(10) COMMENT '老师姓名');
    -- 创建student为从表
    CREATE TABLE IF NOT EXISTS student(
        sid   INT  PRIMARY KEY COMMENT '学生ID',
        sname VARCHAR(10) COMMENT '学生姓名',
        tid INT        COMMENT '引用老师主键的外键字段',
        -- 创建外键并设置级联更新则更新,删除则置空
        CONSTRAINT stu_foreign_tid FOREIGN KEY(tid) references teacher(tid)
         ON UPDATE cascade ON DELETE set null);

删除外键约束:
    -- 第一步先查看约束名和删除外键约束:
    SELECT * FROM information_schema.table_constraints WHERE table_name = 'student';
    +------------------+-----------------+---------------+------------+----------+---------------+
    |CONSTRAINT_CATALOG|CONSTRAINT_SCHEMA|CONSTRAINT_NAME|TABLE_SCHEMA|TABLE_NAME|CONSTRAINT_TYPE|
    +------------------+-----------------+---------------+------------+----------+---------------+
    |def               |testys           |PRIMARY        |testys      |student   |PRIMARY KEY    |
    |def               |testys           |stu_foreign_tid|testys      |student   |FOREIGN KEY    |
    +------------------+-----------------+---------------+------------+----------+---------------+
    -- 第二步删除外键:
    ALTER TABLE student DROP FOREIGN KEY stu_foreign_tid;
    -- 第三步查看索引名和删除索引(因为创建外键后,当前的外键字段会默认创建一个非唯一索引,默认和外键名称一样)
    SHOW INDEX FROM student; 
    ALTER TABLE student DROP INDEX stu_foreign_tid;    

总结:建和不建外键约束有什么区别?
    建外键约束,你的操作(创建表、删除表、添加、修改、删除)会受到限制,从语法层面受到限制。
    不建外键约束,你的操作(创建表、删除表、添加、修改、删除)不受限制,要保证数据的引用完整
    性,只能依 靠程序员的自觉 ,或者是在Java程序中进行限定 。
    例如:在学生表中,可以添加一个学生的信息,它的老师字段可能引用一个根本不存在的老师表信息。

在 MySQL 里,外键约束是有成本的,需要消耗系统资源。对于大并发的SQL操作,有可能会不适合。比如大型网站的中央数据库,
可能会 因为外键约束的系统开销而变得非常慢 。所以,MySQL允许你不使用系统自带的外键约束,在应用层面完成检查数据一致性的逻辑。
也就是说,即使你不用外键约束,也要想办法通过应用层面的附加逻辑,来实现外键约束的功能,确保数据的一致性。

阿里开发规范
    【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
     说明:(概念解释)学生表中的student_id是主键,那么成绩表中的student_id则为外键。如果更新学生表中的student_id,
   同时触发成绩表中的student_id更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新
   是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度

7:CHECK约束(MySQL8.0+支持)

  主要检查某个字段的值是否符合要求,一般指的是值的范围;但MySQL5.7可以使用check约束,但check约束对数据验证没有任何作用。添加数据时,没有任何错误或警告

关键字:CHECK
示例:
    CREATE TABLE IF NOT EXISTS demo_check1(
        id      INT          PRIMARY KEY                                COMMENT '主键ID',
        name     VARCHAR(10)                                            COMMENT '姓名',
        sex     CHAR(1)     CHECK(sex = '男' OR sex = '女')              COMMENT '性别,限制男和女',
        -- 设置限制;必须大于等于500小于等于800
        salary DECIMAL(5,2) CHECK(salary <= 800.00 AND salary >=500.00) COMMENT '设置工资',
        -- 设置身高字段约束,使用表级约束
        height INT                                                      COMMENT '身高',
        CONSTRAINT `demo_check_height` CHECK(height >= 100) );

查询创建表信息:
    show create table demo_check1\G
    *************************** 1. row ***************************
           Table: demo_check1
    Create Table: CREATE TABLE `demo_check1` (
      `id` int NOT NULL COMMENT '主键ID',
      `name` varchar(10) DEFAULT NULL COMMENT '姓名',
      `sex` char(1) DEFAULT NULL COMMENT '性别,限制男和女',
      `salary` decimal(5,2) DEFAULT NULL COMMENT '设置工资',
      `height` int DEFAULT NULL COMMENT '身高',
      PRIMARY KEY (`id`),
      CONSTRAINT `demo_check1_chk_1` CHECK (((`sex` = _utf8mb4'') or (`sex` = _utf8mb4''))),
      CONSTRAINT `demo_check1_chk_2` CHECK (((`salary` <= 800.00) and (`salary` >= 500.00))),
      CONSTRAINT `demo_check_height` CHECK ((`height` >= 100))
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
在修改表时添加检查约束:
    ALTER TABLE <数据表名> ADD CONSTRAINT <检查约束名> CHECK(<检查约束>)
    示例:ALTER TABLE demo_check1 ADD CONSTRAINT demo_check_sex1 CHECK(sex = '' OR sex = '')
删除约束:
    ALTER TABLE <数据表名> DROP CONSTRAINT <检查约束名>;
    示例:ALTER TABLE demo_check1 DROP CONSTRAINT demo_check1_chk_1;

8:默认值约束(DEFAULT)

  主要就是给某个字段或某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默认值。

关键字:DEFAULT
基本语法:
    CREATE TABLE IF NOT EXISTS 表名称(
        字段名1 数据类型 PRIMARY KEY,
        字段名2 数据类型 UNIQUE KEY NOT NULL,
        字段名3 数据类型 UNIQUE KEY,
        字段名4 数据类型 NOT NULL DEFAULT 默认值 );
    注:默认值约束一般不在唯一键和主键列上加
示例:
    CREATE TABLE IF NOT EXISTS demo_default1(
        id INT PRIMARY KEY,
        name VARCHAR(20) NOT NULL,
        sex CHAR(1) DEFAULT '',
        tel char(11) NOT NULL DEFAULT '' -- 默认是空字符串
    );
DESC demo_default1;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | NO   |     | NULL    |       |
| sex   | char(1)     | YES  |     ||       |
| tel   | char(11)    | NO   |     |         |       |
+-------+-------------+------+-----+---------+-------+

在已经存在的表里加默认值(其实就是使用DDL语句修改字段):
    ALTER TABLE 表名称 MODIFY 数据类型 [NOT NULL] DEFAULT 默认值
    -- 注:若字段原来有非空约束则需要加上,删除默认值也是同理,剔除即可

总结:为什么建表时,加not null default '' 或 default 0;为什么不想要NULL值
    不好比较。null是一种特殊值,比较时只能用专门的is null 和 is not null来比较。
    碰到运算符,通常返回null;并且效率不高。影响提高索引效果。因此,
    我们往往在建表时 not null default '' 或 default 0

七:MySQL大小写规范

  在SQL中,关键字和函数名是不用区分字母大小写的,比如SELECT、WHERE、ORDER、GROUP BY等关键字,以及 ABS、MOD、ROUND、MAX等函数名。不过在SQL中,你还是要确定大小写的规范,因为在Linux和Windows环境下,你可能会遇到不同的大小写问题。Windows系统默认大小写不敏感,但是linux系统是大小写敏感的。

Ⅰ:我们可以通过SQL语句进行大小写规则查询:
    SHOW VARIABLES LIKE '%lower_case_table_names%';
    Windows系统下查询:
        +------------------------+-------+
        | Variable_name          | Value |
        +------------------------+-------+
        | lower_case_table_names | 1     |
        +------------------------+-------+
    Linux系统下查询:
        +------------------------+-------+
        | Variable_name          | Value |
        +------------------------+-------+
        | lower_case_table_names | 0     |
        +------------------------+-------+
Ⅱ:lower_case_table_names参数值的说明:
    设置0:默认为0,大小写敏感。
    设置1:大小写不敏感。创建的表,数据库都是以小写形式存放在磁盘上,对于sql语句都是转换为小写对表和数据库进行查找。
    设置2:创建的表和数据库依据语句上格式存放,凡是查找都是转换为小写进行。

Ⅲ:Windows和Linux平台上SQL大小写的区别具体来说:
    MySQL在Linux下数据库名、表名、列名、别名大小写规则是这样的
        ①:数据库名、表名、表的别名、变量名是严格区分大小写的;
        ②:关键字、函数名称在 SQL 中不区分大小写;
        ③:列名(或字段名)与列的别名(或字段别名)在所有的情况下均是忽略大小写的;
    MySQL在Windows的环境下全部不区分大小写

补充基本测试:
    CREATE DATABASE demo_db5;
    USE demo_db5;
    CREATE TABLE demo_db5.demo_t1(`sname` varchar(10));
    Windows下测试(不区分大小写,我表名大写也不报错):
        SELECT * FROM DEMO_T1;
    Linux下测试(区分大小写,特别是数据库名、表名、表的别名、变量名是严格区分大小写的)
        SELECT * FROM DEMO_T1;
        ERROR 1146 (42S02): Table 'demo_db5.DEMO_T1' doesn't exist

1:Linux下大小写规则设置(不建议修改)

在Linux系统下设置大小写不敏感:
MySQL5.7版本下设置大小写不敏感:
        ①:修改配置文件 vim /etc/my.cnf
        ②:在my.cnf里的[mysqld]里加入 lower_case_table_names=1 后重启MySQL服务
        注:修改参数后重启数据库实例之前就需要将原来的数据库和表转换为小写,
            否则虽然可以查看到这个数据库或者数据表,但是无法使用到这个数据库名。
MySQL8.0版本下设置大小写不敏感:
        在MySQL8.0下禁止在重新启动MySQL服务时将lower_case_table_names设置成不同于初始化MySQL服务时设置的
        lower_case_table_names值。如果非要将MySQL8设置为大小写不敏感,具体步骤为:
            ①:停止MySQL服务
            ②:删除数据目录,即删除 /var/lib/mysql 目录
            ③:在MySQL配置文件( /etc/my.cnf )里的[mysqld]添加 lower_case_table_names=1
            ④:启动MySQL服务
            注:把/var/lib/mysql目录下删除,就相当和重装数据库没什么区别(都删了)

2:SQL编写建议

如果你的变量名命名规范没有统一,就可能产生错误。这里有一个有关命名规范的建议:
    ①:关键字和函数名称全部大写;
    ②:数据库名、表名、表别名、字段名、字段别名等全部小写;
    ③:SQL 语句必须以分号结尾。
数据库名、表名和字段名在Linux MySQL环境下是区分大小写的,因此建议你统一这些字段的命名规则,比如全部采用小写的方式。
虽然关键字和函数名称在 SQL 中不区分大小写,也就是如果小写的话同样可以执行。但是同时将关键词和函数名称全部大写,
以便于区分数据库名、表名、字段名。

.

posted @ 2023-05-31 09:14  蚂蚁小哥  阅读(1511)  评论(0)    收藏  举报