Tho*_*mas 5 database-design foreign-key-relationship
我正在为本地城市页面设计数据模型,更像是对它的要求.
所以4个表:国家,州,城市,邻里.
现实生活中的关系是:国家拥有多个州,拥有多个城市,这些城市拥有多个社区.
在数据模型中:我们是否以相同的方式将这些链接与FK或每个链接?就像在每个表中一样,甚至会有一个国家ID,州ID,城市ID和NeighbourhoodID,所以每个都与每个?从国家到达邻居的其他方面我们需要加入其他两个表格吗?
我需要为城市的IP地址,纬度/经度等维护更多的表格.
与行业标准最接近的是:每个从属表都通过外键链接到其直接父级:
create table country
(country_id number not null
, country_name varchar2(30)
, constraint country_pk primary key (country_id)
)
/
create table state
(state_id number not null
, state_name varchar2(30)
, country_id number not null
, constraint state_pk primary key (state_id)
, constraint state_country_fk foreign key (country_id)
references country(country_id)
)
/
create table city
(city_id number not null
, city_name varchar2(30)
, state_id number not null
, constraint city_pk primary key (city_id)
, constraint city_state_fk foreign key (state_id)
references state(state_id)
)
/
create table neighbourhood
(neighbourhood_id number not null
, neighbourhood_name varchar2(30)
, city_id number not null
, constraint neighbourhood_pk primary key (neighbourhood_id)
, constraint neighbourhood_city_fk foreign key (city_id)
references city(city_id)
)
/
Run Code Online (Sandbox Code Playgroud)
另一种基本上不受欢迎的方法是将子表的主键定义为复合键,包括直接父表的键:
create table state
(country_id number not null
, state_id number not null
, state_name varchar2(30)
, constraint state_pk primary key (country_id, state_id)
, constraint state_country_fk foreign key (country_id)
references country(country_id)
)
/
create table city
(country_id number not null
, state_id number not null
, city_id number not null
, city_name varchar2(30)
, constraint city_pk primary key (country_id, state_id, city_id)
, constraint city_state_fk foreign key (country_id, state_id)
references state(country_id, state_id)
)
/
create table neighbourhood
(country_id number not null
, state_id number not null
, city_id number not null
, neighbourhood_id number not null
, neighbourhood_name varchar2(30)
, constraint neighbourhood_pk primary key (country_id, state_id, city_id, neighbourhood_id)
, constraint neighbourhood_city_fk foreign key (country_id, state_id, city_id)
references city(country_id, state_id, city_id)
)
/
Run Code Online (Sandbox Code Playgroud)
这种方法已被弃用,因为在短期内它会产生非常笨拙的连接,并且从长远来看,它会在键变化时产生可怕的混乱.主键不应该改变,但复合它们会产生意义.因此,当系统的数据发生变化时 - 比如国家边界重组 - 对一大堆城市的变化必须级联到邻居表和其他任何子项.呸.
您的提案是此替代版本:
create table state
(state_id number not null
, state_name varchar2(30)
, country_id number not null
, constraint state_pk primary key (state_id)
, constraint state_country_fk foreign key (country_id)
references country(country_id)
)
/
create table city
(city_id number not null
, city_name varchar2(30)
, country_id number not null
, state_id number not null
, constraint city_pk primary key (city_id)
, constraint city_country_fk foreign key (country_id)
references country(country_id)
, constraint city_state_fk foreign key (state_id)
references state(state_id)
)
/
create table neighbourhood
(neighbourhood_id number not null
, neighbourhood_name varchar2(30)
, country_id number not null
, state_id number not null
, city_id number not null
, constraint neighbourhood_pk primary key (neighbourhood_id)
, constraint neighbourhood_country_fk foreign key (country_id)
references country(country_id)
, constraint neighbourhood_state_fk foreign key (state_id)
references state(state_id)
, constraint neighbourhood_city_fk foreign key (city_id)
references city(city_id)
)
/
Run Code Online (Sandbox Code Playgroud)
它避免了复合键,但仍然存在级联数据问题.它也违反了关系实践,为不存在的关系引入了外键(邻域和国家之间没有直接关系,它通过中间联系隐含).
从正面来看,这对于运行想要返回给定国家/地区的邻居的查询非常有用.我曾经在一个有用的系统上工作(实际上它使用了继承的复合键,但原理是相同的).但是,这是一个非常专业的数据仓库,即便如此,我运行的查询是管理员/开发人员查询而不是应用程序查询.除非您处理大量数据(数百万个邻域),否则我认为跳过几个连接所带来的性能提升不值得管理这些额外列的开销.
简而言之,使用第一种方法:它很整洁而且是标准的.
编辑
"国家应该是可选的,因为并非所有国家都有州.然后一个国家将直接与城市联系."
如果是真的,那就会改变一切.显然,STATE不能用作CITY的标识外键.所以CITY必须参考COUNTRY.STATE可以是CITY上的可选查找.
虽然我认为大多数国家都有一些等同的细分,如县或部门.甚至像利希滕斯坦和圣马力诺这样的微观状态也有市政当局(摩纳哥只有一个).也许唯一没有的国家是梵蒂冈城.因此,请仔细考虑是否构建数据模型以支持一个或两个边缘情况,或者通过为诸如罗马教廷等例外注入人为的"状态"来挖掘数据.这两种方法都不完全令人满意.
"所有这些字段都是自动完成的字段,所以不确定是否会改变表结构?"
没有区别.
"但谁知道,几个月后我们可能会发现一些很酷的功能,可能需要国家与社区相匹配."
是的但是你可能不会.XP有一个强大的原则叫YAGNI - 你不需要它.基本上,为了一些可能永远不会到来的假定的未来要求,不要做很多工作并使设计复杂化.
如果它确实到达那么第一个解决方案是通过中间表(或表,如果你不使用STATE作为CITY的引用)加入NEIGHBORHOOD和COUNTRY.只有当该查询的性能是Teh Suck时!如果你考虑调整数据模型,它就会顽固地抵制调整.