数据库设计101

时间:2011-12-10 19:11:16

标签: database-design

我有一个关于数据库设计的非常基本的问题。我以为我知道答案,但在看了三重下拉菜单的在线教程和演示数据库的设计后,我不再那么肯定了。

好的,这是设置,涉及三个表。

第一张表:tblcountry 字段:country_id 国家

第二个表:tblstate 字段:state_id COUNTRY_ID 状态

第三表:tblcity 字段:cidy_id STATE_ID 城市

现在我的问题是:在表3中,是否还需要包含countryid?通过使用SQL,您可以查询该城市所在的国家/地区....或者在城市表中引用该国家/地区是否是一个好的设计?

我希望有人可以提供帮助:-)

3 个答案:

答案 0 :(得分:6)

简短的回答,正确的99.9%的时间:不。你已经通过州记录提到了这个国家。

答案很长,0.1%的时间:您可能需要从城市直接引用该国家/地区,因为您对一个国家/地区的城市有很多查询,并在查询中添加第二个表格将使查询花费更长时间。

当然,对于城市,州和国家/地区的记录集,第二种情况不太可能,但对于其他类型的数据,如果您管理大量记录,则很可能。

编辑:在我的工作中,我有很多这样的情况,我只是在表格中保留额外的三个或四个参考级别。这些是庞大的数据库,并且在所有常见查询中放置中间表确实会对数据库产生压力(每个查询使用的内存更多)。所以我会从没有直接引用开始,然后根据需要添加“快捷方式”字段。这涉及到解决可伸缩性问题的问题,这超出了初学者级别的问题。此外,如果您在下游表格中添加快捷方式字段,那么这是您的应用程序的额外断点(当您将城市更新到另一个国家/地区时要更新两条记录),因此请记住这一点。

答案 1 :(得分:3)

  

在表3中,是否还需要包含countryid?

没有

您可以使用以下查询获取county_id:

SELECT country_id 
FROM tblcity c
INNER JOIN tblstate s ON (c.state_id = s.state_id)

如果您执行在城市表中包含country_id,则您的数据库会违反正常格式,因为数据会重复,并且存在数据不同步的危险。例如。如果country_id中的tableCitytableState中的SELECT co.country FROM tblcity ci INNER JOIN tblstate s ON (ci.state_id = s.state_id) INNER JOIN tblCountry co ON (s.country_id = co.country_id) 不匹配,会发生什么。

如果您想获得国家/地区名称,您还需要加入该国家/地区:

city-> state -> country

另请注意,划分:{{1}}是一个非常以美国为中心的观点,并非所有国家都是这样划分的,在某些国家/地区需要四个级别的层次结构。

答案 2 :(得分:1)

规范化从数据开始。在下文中,松散地使用 state 这个词。我说的是数据分析和规范化,而不是关于政治层级的建模。

country_name               state_name  city_name
--
United States of America   Alabama     Birmingham
United States of America   California  Atascadero
United States of America   Florida     Key Largo
United States of America   Illinois    Carbondale
United States of America   Kentucky    Winchester
United States of America   Michigan    St. Louis
United States of America   Ohio        Coldwater
United States of America   Montana     Glasgow
United States of America   Louisiana   Jefferson
United States of America   Wisconsin   Jefferson
Bulgaria                   Montana     Montana
Costa Rica                 San José    San José
Argentina                  Entre Rios  San José
Uruguay                    San José    San José de Mayo

表示“City [city_name]处于国家[country_name]的州[state_name]。” (表的含义称为谓词。)

此表有效地将城市的“全名”标识为{country_name,state_name,city_name}。在概念层面,它与使用{last_name,middle_name,first_name}来识别一个人没有什么不同。不同的是,虽然两个人经常共用同一个全名,但两个城市却没有。

很明显,只有一个候选键:{country_name,state_name,city_name}。此表格为5NF。用ID号替换文本不能改变它。

现在, 之后 是吗,“好的,现在我需要将拆分成更多的表吗?”

我希望不会。

为了提高数据完整性,您可以project列的合理子集,并设置外键引用。以这种方式使用的投影对原始表格的正常形式完全没有影响。如果在这种投影之前它在2NF,那么在这种投影之后它将在2NF。这些表与原始表的谓词略有不同。 (咄。)

-- Predicate: "State [state_name] is in country [country_name]."
-- This table is also in 5NF.
create table states (
  country_name varchar(35) not null,
  state_name varchar(15) not null,
  primary key (country_name, state_name)
);

insert into states
select distinct country_name, state_name
from cities;

alter table cities
add constraint cities_fk1
foreign key (country_name, state_name)
  references states (country_name, state_name);

-- Predicate: "[country_name] is a country."
-- This table is also in 5NF.
create table countries (
  country_name varchar(35) primary key
);

insert into countries
select distinct country_name 
from states;

alter table states
add constraint states_fk1
foreign key (country_name)
  references countries (country_name);

要选择国家/地区来填充下拉列表,您可以

select country_name
from countries
order by country_name;

用户选择了一个国家,选择状态很简单。

select state_name
from states
where country_name = '?'
order by state_name;

选择城市名称是相似的。

select city_name 
from cities
where country_name = '?' 
  and state_name = '?'
order by city_name;