前言:数据库设计中,如果这样设计可能会出错则这种设计就是不对的
1:外键不要设计为表的主键(注意是不要而不是不能,外键是可以作为表的主键的,但实际应用中那样设计几乎没有吧,此处请仔细想 )
2:被指向的键必须具有唯一性
外键约束了什么?
约束,被设为外键的那一字段中的值都必须出现在 被引用的列中
案例
现在有三个表
dish(dish_id)
order(order_id)
order_detail(order_id,dish_id)
我在order_detail里对order_id , dish_id设为外键,分别指向order.order_id,dish.dish_id
外键保证了什么?
首先保证了order_detail中order_id , dish_id 这两个字段中的值都出现在了order.order_id,dish.dish_id中,
并且保证了当order,dish 这两个表中某一个表删除某一行A时必须删除order_detail中包含A.order_id/A.dish_id的行,否则删除不了
这样就保证了数据的一致性和完整性
什么时候用外键?
这个问题,其实就是看能不能满足设置外键的条件以及业务需求必要性。在我看来,如果使用了外键,则两个表就产生了连带责任:删除主的则必须删除从的,删除从的不必删除主的。如果业务需求中需要实现这种连带责任的业务需求,就要使用外键。
为什么被指向的列必须具有唯一性?
比如我现在想保证checkout_staff中的值都出现在staff表的name列中
可以看出目前没有问题,但是删除staff表中staff_id为13/20的行的时候删除不了,如果想删除,只能先删除bill表中包含"经理"的行,但是这样会出现问题,因为bill表中包含"经理"的行既有可能是staff_id为13的员工,也有可能是staff_id为20的员工,所以删除的时候会出错。现在有的同学问了,那我把bill中的checkout_staff换成staff_id不就行了吗,这就要考虑实际应用中的需求了,如果我们因为员工离职,现在要把这个员工从staff表中删除,难道我就要历史账单也删掉吗?那肯定是不行的万一哪天账单出了问题,核对都核对不了。所以上图中的数据库设计,也不是说不对,因为需求是那样。没办法强求保证checkout_staff中的值都出现在staff表的name列中,所以这里设置外键是没办法设置的。那怎么保证checkout_staff中的值都出现在staff表的name列中?其实不用保证,checkout_staff中的值也都出现在staff表的name列,不过需要前后端数据保持一致就行了
为什么外键可以是表的主键但不要那样设计?
其实这个问题很弱智,因为既然外键都可以允许有重复值了,那么不允许有重复值又能怎样呢?
其实这种说法是没问题的,并且这样建表也是没问题的。
但是在实际应用中会这样设计吗?一个表的主键是另一个表主键的子集?