*P03 DB 数据库的约束条件、表关系、修改表语法以及复制表*

时间:2020-06-19 23:46:00 来源:互联网 作者: 神秘的大神 字体:

内容概要

  • 约束条件
  • 表与表之间建立关系(约束)
  • 修改表的完整语法
  • 复制表

约束条件

default默认值

"""
# 补充:在插入数据的时候可以指定字段
create table t1 (
    id int, 
    name varchar(16)
);

insert into t1 (name, id) values ('samuel', 1);

create table t2 (
    id int, 
    name varchar(16),
    gender enum('male', 'female', 'others') default 'male'
);

insert into t2 (id, name) values (1, 'samuel');
insert into t2 values (2, 'nagase', 'female');
"""

unique唯一

"""
# 单列唯一
create table t3 (
    id int unique,
    name varchar(16)
);

insert into t3 values (1, 'samuel'), (1, 'nagase');
insert into t3 values (1, 'samuel'), (2, 'nagase');

# 联合唯一
# ip和port,单个可以重复,但是加在一起必须是唯一的
create table t4 (
    id int, 
    ip varchar(16),
    port int,
    unique (ip, port)
);

insert into t4 values (1, '192.168.1.1', 8000);
insert into t4 values (2, '192.168.1.1', 8001);
insert into t4 values (3, '192.168.1.2', 8000);
insert into t4 values (4, '192.168.1.1', 8000);
"""

primary key主键

"""
# 单单从约束效果上来看,primary key等价于not null + unique
# 非空且唯一!!!
create table t5 (
    id int primary key
);

insert into t5 values (null);
insert into t5 values (1), (1);
insert into t5 values (1), (2);

# 它除了有约束效果之外,它还是Innodb存储引擎在组织数据的依据。
# Innodb存储引擎在创建表的时候必须有primary key
# 因为它类似于书的目录,能够帮助提升查询效率,并且也是建表的依据

# 1、一张表中,有且只有一个主键,如果没有设置主键,那么会从上至下搜索,直到遇到一个非空且唯一的字段将其升级为primary key
create table t6 (
    id int,
    name varchar(16), 
    age int not null unique, 
    addr varchar(32) not null unique
);
# 2、如果表中没有主键也没有其他任何的非空且唯一字段,那么Innodb会采用自己内部提供的一个隐藏字段作为primary key,隐藏意味着你无法使用它,进而就无法提升查询效率

# 3、一张表中通常都应该有一个主键字段,并且通常将id作为主键
# 单个字段主键
create table t7 (
    id int primary key,
    name varchar(16)
);
# 联合主键(多个字段联合起来作为表的主键,本质还是一个主键)
create table t7 (
    ip varchar(16),
    port int,
    primary key (ip, port)
);
"""

auto_increment自增

"""
# 当编号特别多的时候,人为的去维护太过繁琐,因此这就涉及到了自增
create table t8 (
    id int primary key auto_increment,
    name varchar(16)
);

insert into t8 (name) values ('samuel'), ('nagase'), ('matthew');
# 注意:auto_increment通常都是加在primary key键上,不能给普通字段加
"""

补充:删除表的两种方法

"""
delete from 表名

truncate 表名
"""

两种方法的区别:delete from 表名这种方法,在删除表中数据的时候,主键的自增不会停止,会继续编号

然而,truncate 表名这种方式,除了清空数据表之外还会重置主键的自增,使其从1重新开始

表与表之间建立关系

"""
# 定义了一张员工表 表中有很多字段
# id name gender dep_name dep_desc

# 分析目前的表所存在的问题:
# 1、该表的组织结构不是很清晰
# 2、浪费磁盘空间
# 3、数据的扩展性极差

# 那么该如何优化呢?那么多的字段全部写在了一张表里,那就相当于把所有的代码全部写在一个文件中,这样是有极大问题的。
# 因此我们应该将该表拆分为:员工表和部门表
"""

外键约束

# 外键就是用来帮助我们建立表与表中间关系的
foreign key

表与表之间的关系

# 表与表之间的关系只有4种

# 一对多关系
    # 注意:在MySQL中,没有多对一关系这么一说,一对多、多对一 ,都是一对多
# 多对多关系
# 一对一关系
# 没有关系

一对多关系

"""
判断表与表中间关系的时候,一定要一步一步的判断,使用正确的方法,那就是
“换位思考”分别站在两张表的角度考虑问题

比如:员工表与部门表
先站在员工表
    思考一个员工能够对应多个部门------不能!!!
再站在部门表
    思考一个部门可以不可以包含多个员工-------可以!!!
得出结论:
    员工表与部门表表示单向的一对多,所以表关系就是一对多。
"""
foreign key
【原则1】一对多关系的表 外键字段要建立在多的那一方
【原则2】在创建表的时候,一定要先创建被关联的那一方

# SQL语句
create table dep (
    id int primary key auto_increment,
    dep_name varchar(16),
    dep_desc varchar(32)
);

create table emp (
    id int primary key auto_increment,
    name varchar(16), 
    gender enum('male', 'female', 'others') default 'male',
    dep_id int,
    foreign key (dep_id) references dep (id)
);

insert into dep (dep_name, dep_desc) values ('教学部', '教书育人'), ('技术部', '技术能力有限'), ('外交部', '外交');

insert into emp (name, dep_id) values ('samuel', 2), ('nagase', 1), ('matthew', 1), ('garnet', 3);

# 修改dep表的id字段
update dep set id = 200 where id = 2;    操作失败

# 删除dep表里的数据
delete from dep;    操作失败

以上两个语句都失败了,是因为dep表被emp表所引用,因此,dep表不可以被删除。解决办法如下:
# 1、先删除教学部对应的员工数据,之后再删除部门
 这样做太过繁琐

# 2、真正做到数据之间有关系,更新就同步更新,删除就同步删除
# 那也就是级联更新、级联删除,那么如何做到呢???
# 解决办法:在创建表的时候添加额外的约束
create table dep (
    id int primary key auto_increment,
    dep_name varchar(16),
    dep_desc varchar(32)
);

create table emp (
    id int primary key auto_increment,
    name varchar(16),
    gender enum('male', 'female', 'others') default 'male',
    dep_id int,
    foreign key(dep_id) references dep(id) on update cascade on delete cascade
);

多对多关系

"""
判断表与表之间关系的时候,一定要使用正确的方法,那就是“换位思考”,分别站在两张表的角度考虑

例如:图书表与作者表
先站在图书表的角度考虑,思考一个图书可不可以有多个作者-----可以!!!
再站在作者表的角度考虑,思考一个作者可不可以出版多本图书----可以!!!
得出结论:
图书表与作者表是双向的一对多,所以表关系就是“多对多”关系
"""
create table book (
    id int primary key auto_increment,
    title varchar(32),
    price int, 
    author_id int,
    foreign key(author_id) references author(id) on update cascade on delete cascade
);

create table author (
    id int primary key auto_increment,
    name varchar(32), 
    age int, 
    book_id int, 
    foreign key(book_id) references book(id) on update cascade on delete cascade
);

# 如果按照以上的语句创建表,结果是:::失败的!!!
回想我们的两大原则:
【原则1】针对于一对多关系的表,外键字段要建立在多的那一方
【原则2】在创建表的时候,一定要先创建被关联的那一方
针对于图书表与作者表,图书表引用了作者表的id,对于图书表来说,作者表是被关联的那一方;那么反过来,对于作者表来说,图书表是被关联的那一方,如此一来,双方都是被关联的那一方,那,,,,怎么办。。。双方就这么拖着。。。于是乎两张表均创建失败!!!

# 其实我们只是想记录图书与作者的关系
# 针对多对多的关系,不能在两张原表中创建外键
# 我们需要单独创建一张表出来专门用于存储两张表之间的关系
create table book (
    id int primary key auto_increment,
    title varchar(16),
    price int
);

create table author (
    id int primary key auto_increment, 
    name varchar(16), 
    age int
);

create table book2author (
    id int primary key auto_increment, 
    book_id int, 
    author_id int,
    foreign key(book_id) references book(id) on update cascade on delete cascade,
    foreign key(author_id) references author(id) on update cascade on delete cascade
);

一对一关系

"""
id name age gender addr phone hobby email...
如果一张表的字段特别多,每次查询又不是所有的字段都能用到,于是我们将表一分为二
用户表
    id name age
用户详情表
    id addr phone hobby email...

“换位思考”的方法:
先站在用户表的角度考虑:一个用户能否对应多个用户详情----不可以!!!
再站在用户详情的角度考虑:一个用户详情是否属于多个用户---不可以!!!
得出结论:单向的一对多都不成立,那么这个时候两者之间的关系要么就是一对一的关系要么就是没有关系
注意,针对于一对一的关系,外键字段要建立在查询频率高的那张表中
"""
create table user_detail (
    id int primary key auto_increment,
    phone int,
    addr varchar(64)
);

create table user (
    id int primary key auto_increment,
    name varchar(16),
    age int,
    user_detail_id int unique,
    foreign key(user_detail_id) references user_detail(id) on update cascade on delete cascade 
);

总结

"""
表关系的创建需要用到foreign key
    一对多
        外键字段建立在多的一方
    多对多
        自己开设第三张表
    一对一
        建立在任意一张表中都可以,但是建议在查询频率高的表中建立
        
建立表之间关系的方式
    换位思考!!!
        员工 与 部门
        图书 与 作者
        用户 与 用户详情
"""

修改表

# MySQL对大小写是不敏感的
# 1、修改表名
alter table 表名 rename 新表名;

# 2、增加字段
alter table 表名 add 字段名 字段类型(宽度) 约束条件; # 默认是加在表的最后
alter table 表名 add 字段名 字段类型(宽度) 约束条件 first; # 加在表的开头
alter table 表名 add 字段名 字段类型(宽度) 约束条件 after 字段名; # 手动说明要加在哪里

# 3、删除字段
alter table 表名 drop 字段名;

# 4、修改字段
alter table 表名 modify 字段名 字段类型(宽度) 约束条件;
alter table 表名 change 旧字段名 新字段名 字段类型(宽度) 约束条件;

复制表

# 我们在执行SQL语句的时候,显示的结果是一张虚拟的表
create table 新表名 select * from 表名; # 但是不可以复制主键、外键、索引...只是复制了结构和数据而已