数据库中为什么需要外键?

此文将以如何将用户taobao的用户信息及其多个邮寄地址保存到数据库的三个方案为例来说明数据库中为什么需要外键(本文使用的是Navicat Premium可视化数据库管理工具来操作数据库)

方案一:

create table user_info(
id char(36) primary key,
#primary key:指定主键。该约束强制字段或字段组合必须具有唯一性且每个字段不能为空。可以为字段级别约束,也可以为表级别约束。
#注:此行代码中的id是用来表明每一组数据唯一性的,往后不再赘述
user_name varchar(30) not null,
#not null:指定字段不能为空,只能定义为字段级约束
password varchar(30) not null,
real_name varchar(8),
mobile char(11),
address varchar(150)
);
#建立一个表格,用于存储用户taobao的用户信息
insert into user_info (id,user_name,password,real_name,mobile,address) 
values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','taobao','123456','张三','18920120206','辽宁大连');
insert into user_info (id,user_name,password,real_name,mobile,address) 
values ('cc95772b-75a2-4702-bd99-4c3b0322d606','taobao','123456','李四','18617297545','河南南阳');
insert into user_info (id,user_name,password,real_name,mobile,address)
values ('c63028fd-cf8d-4dac-a278-b5cc8fd61e3c','taobao','123456','王五','17694976949','山东合肥');
#往表中加入三组taobao用户的邮寄信息

如下是建立此表并添加信息后的查询结果

查询结果

此种方案存储用户不同邮寄地址信息缺点很明显,即这种表结构存在严重的字段冗余(user_name和password列),如果个人信息字段比较多这一问题表现的越严重。

方案二:

create table user_info(
id char(36) primary key,
user_name varchar(30) not null,
password varchar(30) not null
)
#首先建立一个名为user_info的表格,只用于存储用户名和用户密码
insert into user_info (id,user_name,password) values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','taobao','123456');
#将用户名和密码输入user_info表格
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
)
#再创建一个表格address,用于存储taobao用户的邮寄地址信息(省掉了冗余信息)
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','山东合肥');
#向address表格中插入三组邮寄地址信息

如下为两表查询结果

user_info表格查询结果
数据库中为什么需要外键?_第1张图片

这种表结构虽然消除了字段冗余,但由于只是逻辑上的“外键”关系(真正的外键关系方法三中会详细描述),所以依然无法保证数据完整性,例如可以将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’,‘666666’,‘皮皮虾’,‘18338970095’,‘珠江三角洲’);)——同样,该条数据并不完整,依然找不到这些地址属于哪个用户。
注:上面讲述的是可以对address表中数据进行的操作,而这里也可以在address表中存在与主键值相等的user_info_id数据时删除和修改主键值

这里以往address表格中添加一条user_info_id不存在的地址信息为例来表明这一点(就用上面引言中的插入代码,这里直接展示查询结果):

数据库中为什么需要外键?_第2张图片

很明显上述查询结果中多出了一组数据的user_info_id并非51b28fe1-4ebf-41ac-a17b-d5e276861fd0,而是666666,这明显是错误的,但是却可以输入进去,所以方案二只满足的逻辑上的“外键”是十分不足的

方案三:

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','taobao','123456');
#以上都是方案二的老样子,建一个只有id,用户名和密码的表,并添加一条用户数据
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)
#此行代码为user_info_id添加了外键,指向user_info表的主键,该约束起到了保护数据完整性的作用:如果删除的用户信息id已经在address表中使用,则该条数据无法删除;无法向address表中添加用户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','山东合肥');

此时如果再向address表中添加外键user_info_id值与主键id值不同,则添加不成功并且会报错,报错信息如下:

报错信息

所以经总结可知,与方案一和方案二重没有使用外检约束的方法比较,外键约束不仅保护了数据完整性,并且可以解决数据冗余的问题

你可能感兴趣的:(数据库)