一、我们用电商买家的收货地址为例:
我们都知道一个买家可能会有多个用户信息,在创建表时就会发生数据冗余的现象:
create table user_info(
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 user_info (id,user_name,password,real_name,mobile,address)
values ('51b28fe1-4ebf-41ac-a17b-d5e276861fd0','fuliuqingfeng','123456','张三','18920120206','河南安阳');
insert into user_info (id,user_name,password,real_name,mobile,address)
values ('cc95772b-75a2-4702-bd99-4c3b0322d606','fuliuqingfeng','123456','李四','18617297545','北京海淀');
insert into user_info (id,user_name,password,real_name,mobile,address)
values ('c63028fd-cf8d-4dac-a278-b5cc8fd61e3c','fuliuqingfeng','123456','王五','17694976949','山西大同');
上述代码创建的表中user_name和password重复了三次,如果个人信息字段比较多这一问题表现的越严重。
二、解决方法:
在mysql中外键可以解决这种字段冗余的现象:
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','山西大同');
如上述代码所示,创建两个不同的表将用户信息和收件人信息分开,用user_info_id表示两表之间的关系即可,这就是外键的逻辑关系,但两表并没有真正关联在一起,依然无法保证数据完整性,例如可以将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’,‘北京东城区’);)——同样,该条数据并不完整,依然找不到这些地址属于哪个用户。
三、外键:
我们可以用foreign key(user_info_id) references user_info(id)将两表真正关联在一起:
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,
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不存在的地址信息。