您正在寻求有关何时应考虑对架构进行进一步规范化的建议。
This answer from @KnutBoehnert很详细,我的回答真的是对它的补充。
规范化数据库结构的目标是不是将字段的重复名称减少到单个引用,而是减少存储在这些字段中的数据的重复。要为给定架构提供明确的答案,通常需要您提供一组记录,但是您的数据集足够简单,可以与我们可以讨论一些假设的现实世界规范相关联。
这与 OO 编程中的继承或组合不同,我强烈建议您将这些字段封装为表示这些表中记录的对象之间的公共基类上的属性,或者封装为它们都组成的接口进入他们的结构。
只有当 Country/State/City 的重复字段名称通常具有相同的值时,才有强有力的论据来重构此结构以引入一个单独的表来保存 Language、Flag、Flower、Animal、Bird 的值。
如果您确实为此信息创建了一个单独的表,那么其中的记录多久会被重复使用一次?例如,有多少个不同的国家会引用相同的记录?很可能没有,因为每个国家/地区的国旗通常是唯一的,但所有这些字段的组合肯定会在每个国家/地区都是唯一的。对于状态,相同的陈述通常是正确的。如果没有重复使用这个新表中的记录,如果关系始终是 1:1,那么数据库和查询将按照您现在的方式留在表中进行优化。
1:1 关系确实占有一席之地,特别是如果对于给定的概念记录存在不同的用例,其中一组字段与另一组隔离更新或查询,并且这两组具有非常不同的查询率,但是就其本身而言,无需任何进一步的支持理由,可以通过将两个表合并到一条记录中来简化模式中的 1:1 关系。
例如,如果一个国家内的所有州和一个州内的所有城市都预期具有相同的语言,那么您根本不需要较低级别的字段,您可以使用连接来访问语言字段国家记录。但在现实世界中,有许多国家的州与整个国家的当地语言或方言不同,所以我认为这不适用于这个特定的模式。
事实上,我认为您当前的架构没有理由改变,现在的结构甚至允许您使用空值来指示该值应该从父级别合并。
例如,在澳大利亚,State 和 City 的所有记录的语言值很可能都是 English,我们可以使用空合并语句来避免在每个州输入和维护该值的需要,并且城市记录,因此在澳大利亚,在所有州和城市中,officialLanguage 字段中留下了 null 的值,我们仍然可以从父相关国家/地区合并它:
SELECT
country.Name AS country_name,
country.officialLanguage AS country_language
state.name AS state_name,
IsNull(state.officialLanguage,country.officialLanguage) AS state_language
city.name AS city_name,
COALESCE(city.officialLanguage, state.officialLanguage, country.officialLanguage) AS city_language,
FROM tblCity AS city
INNER JOIN tblState AS state
ON state.Stateid = city.Stateid
INNER JOIN tblCountry AS country
ON country.Countryid = state.Countryid
以这种方式仅查询 city 表的记录可能如下所示:
我不确定合并其他字段是否有意义,但可以这样做
SELECT
CityId,
city.StateId,
state.CountryId,
...
COALESCE(city.officialLanguage, state.officialLanguage, country.officialLanguage) AS officialLanguage,
COALESCE(city.officialFlag, state.officialFlag, country.officialFlag) AS officialFlag,
COALESCE(city.officialFlower, state.officialFlower, country.officialFlower) AS officialFlower,
COALESCE(city.officialAnimal, state.officialAnimal, country.officialAnimal) AS officialAnimal,
COALESCE(city.officialBird, state.officialBird, country.officialBird) AS officialBird,
FROM tblCity AS city
INNER JOIN tblState AS state
ON state.Stateid = city.Stateid
INNER JOIN tblCountry AS country
ON country.Countryid = state.Countryid
在这种空合并概念的许多实际应用中,应用层会以不同的方式处理这些字段的显示,但对于这个问题,我们今天最关心的是存储。