数据库架构问题

时间:2010-06-16 06:36:39

标签: database-design foreign-key-relationship

我正在为本地城市页面设计数据模型,更像是对它的要求。

所以4个表:国家,州,城市,邻居。

现实生活关系是:国家拥有多个州,拥有多个城市,这些城市拥有多个社区。

在数据模型中:我们是否以相同的方式将这些链接与FK或每个链接?就像在每个表中一样,甚至会有一个国家ID,州ID,城市ID和NeighbourhoodID,所以每个都与每个?其他明智的做法是从国家到达邻居我们需要加入其他两个表格吗?

我需要为城市的IP地址,纬度/经度等维护更多的表格。

1 个答案:

答案 0 :(得分:5)

与行业标准最接近的是:每个从属表都通过外键链接到其直接父级:

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)
 )
/

另一种基本上不再受欢迎的方法是将子表的主键定义为复合键,包括直接父表的键:

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)
 )
/

这种方法已被弃用,因为在短期内它会产生非常笨拙的连接,并且从长远来看,它会在键变化时产生可怕的混乱。主键不应该改变,但复合它们会产生意义。因此,当系统的数据发生变化时 - 比如国家边界重组 - 对一大堆城市的变化必须级联到邻居表和其他任何子项。呸。

您的提案是此替代版本:

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)
 )
/

它避免了复合键,但仍然存在级联数据问题。它也违反了关系实践,为不存在的关系引入了外键(邻域和国家之间没有直接关系,它通过中间联系隐含)。

正如你所指出的那样,这对于运行想要返回给定国家/地区的邻居的查询非常有用。我曾经在一个有用的系统上工作(实际上它使用了继承的复合键,但原理是相同的)。但是,这是一个非常专业的数据仓库,即便如此,我运行的查询是管理员/开发人员查询而不是应用程序查询。除非您处理大量数据(数百万个邻域),否则我认为跳过几个连接的性能提升不值得管理这些额外列的开销。

简而言之,使用第一种方法:它很整洁,而且是标准的。

修改

  

“从那以后,国家应该是可选的   并非所有国家都有州。然后一个   国家将与城市连接   直接地“。

如果是真的,那会改变一切。显然,STATE不能用作CITY的标识外键。所以CITY必须参考COUNTRY。 STATE可以是CITY上的可选查找。

虽然我认为大多数国家都有一些等同的细分,例如县或部门。甚至像利希滕斯坦和圣马力诺这样的微观状态也有市政当局(摩纳哥只有一个)。也许唯一没有的国家是梵蒂冈城。因此,请仔细考虑是否构建数据模型以支持一个或两个边缘情况,或者通过为诸如罗马教廷等例外注入人为的“状态”来挖掘数据。这两种方法都不完全令人满意。

  

“所有这些领域都将是   自动完成字段所以不确定是否   改变了表格结构   吗?“

没有任何区别。

  

“但谁知道,几个月后我们   可能会发现一些很酷的功能   可能需要国家匹配   邻居也是。“

是的但是你可能不会。 XP有一个强大的原则叫YAGNI - You're aren't gonna need it。基本上,为了一些可能永远不会到来的假定未来要求,不要做很多工作并使设计复杂化。

如果它确实到达那么第一个解决方案是通过中间表(或表,如果你不使用STATE作为CITY的引用)加入NEIGHBORHOOD和COUNTRY。只有当该查询的性能是Teh Suck时!如果你考虑调整数据模型,它就会顽固地抵制调整。