为什么要有外键

  • 在我们平时使用淘宝或京东购物时,一个用户里面可以有多个收货地址,这时候我们思考一个问题,如何将京东fuliuqingfeng的用户信息及其多个邮寄商品地址保存到数据库中?

下面我们先来看一段数据库中的代码:

方案1:

create table student(
  id char(36) primary key,
  user_name varchar(30) not null,
  password varchar(30) not null,
  real_name varchar(8),
  mobile char(11),
  address varchar(150)
);
insert into student (id,user_name,password,real_name,mobile,address) 
values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','fuliuqingfeng','123456','张三','18920120206','河南安阳');
insert into student (id,user_name,password,real_name,mobile,address) 
values ('cc95772b-75a2-4702-bd99-4c3b0322d606','fuliuqingfeng','123456','李四','18617297545','北京海淀');
insert into student (id,user_name,password,real_name,mobile,address)
values ('c63028fd-cf8d-4dac-a278-b5cc8fd61e3c','fuliuqingfeng','123456','王五','17694976949','山西大同');
select * from student

此时我们在MySQL中执行该语句,并查询,此时得到的执行结果为:

在这里,我们可以看到,此种方法也可以准确地表示出来同一用户的不同收货地址但是,这里有一个问题。我们看到,在user_name和password那一列的信息都是相同的,这样信息录入就重复了,此时在这种表结构中存在着严重的字段冗余,如果个人信息字段越多,这种冗余问题会表现得越严重。

方案 2:

create table user_info(
  id char(36) primary key,
  user_name varchar(30) not null,
  password varchar(30) not null
)
insert into user_info (id,user_name,password) values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','fuliuqingfeng','123456');

create table address(
  id char(36) primary key,
  user_info_id char(36),
  real_name varchar(8) not null,
  mobile char(11) not null,
  address varchar(150) not null
)
insert into address (id,user_info_id,real_name,mobile,address) 
values ('bfb9472a-7911-4e6f-a479-3b719454ebab','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','张三','18920120206','河南安阳');
insert into address (id,user_info_id,real_name,mobile,address) 
values ('5227c6b9-45a2-44aa-8ac0-1f63a38d3b65','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','李四','18617297545','北京海淀');
insert into address (id,user_info_id,real_name,mobile,address) 
values ('30b8584b-aa6a-4516-a623-03f487058586','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','王五','17694976949','山西大同');
select * from address

此时的代码执行为,先把有相同个人信息的列都抽取出来,这时候新建一个user_info的表格,因为用户的用户名具有唯一性,所以可以将每个用户的用户名及密码等个人信息赋一个id值,此时再在user_info的表中将此id设置为一个主键,即表示通过该唯一确定的id可以查找到此时user_info表中的其他存储个人信息的数据。

这时我们将用户不同收获地址的信息存放到一个新的address的表中,此时通过表中的user_info_id就可以查找到用户的信息,这样将一个表拆分成两个表的方式,虽然在一定程度上减少了方案1中表的字段冗余,但由于此时的address表和user_info表只是逻辑上的“外键”关系,所以无法保证数据完整性。

例如可以将user_info中id为51b28fe1-4ebf-41ac-a17b-d5e276861fd0的数据删除,但此时地址表中数据将不再完整——找不到这些地址属于哪个用户;再例如也可以向address表中添加一条user_info_id不存在的地址信息(如:insert into address (id,user_info_id,real_name,mobile,address) values ('7da42cc6-36a6-4ad5-9998-71dbc30c8e17','ddc376dd-f8b3-42a6-b42a-db22abed1941','xiaowang','18338970095','北京东城区');)——同样,该条数据并不完整,依然找不到这些地址属于哪个用户。这时候这些不完整的数据信息对我们来说就是没有用的信息了,因为此时你可能不知道一条地址对应的用户是谁,这时候这些没有用的数据就被称为“脏数据”。

由此,我们可以看出方案2因其无法保证数据的完整性,所以也是不可行的。

为了解决方案 1 和方案 2 的问题,即在解决字段冗余的同时,还可以确保数据的完整性,这时我们就引入了外键

方案 3:

create table user_info(
  id char(36) primary key,
  user_name varchar(30) not null,
  password varchar(30) not null
)
insert into user_info (id,user_name,password) values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','fuliuqingfeng','123456');

create table address(
  id char(36) primary key,
  user_info_id char(36),
  real_name varchar(8) not null,
  mobile char(11) not null,
  address varchar(150) not null,
  constraint address_user_info_id_fk foreign key(user_info_id) references user_info(id)
)
insert into address (id,user_info_id,real_name,mobile,address) 
values ('bfb9472a-7911-4e6f-a479-3b719454ebab','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','张三','18920120206','河南安阳');
insert into address (id,user_info_id,real_name,mobile,address) 
values ('5227c6b9-45a2-44aa-8ac0-1f63a38d3b65','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','李四','18617297545','北京海淀');
insert into address (id,user_info_id,real_name,mobile,address) 
values ('30b8584b-aa6a-4516-a623-03f487058586','51b28fe1-4ebf-41ac-a17b-d5e276861fd0','王五','17694976949','山西大同');

此时代码的执行结果为:

说明:外键就是外来的主键,这种方案为user_info_id添加了外键,指向user_info表的主键,该约束起到了保护数据完整性的作用:如果删除的用户信息id已经在address表中使用,则该条数据无法删除;无法向address表中添加用户id不存在的地址信息。

还需注意的是,如果要想删除user_info表中的数据,此时需要先drop table address,即清空address表,在address表中用到user_info_id信息的同时,因为此时为user_info_id为外来的主键,所以该条数据无法删除

如果想删除此时的user_info表或者是清空user_info表中的数据,此时就需要先删除address的表:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值