sql - 以国家为列的数据库中的规范化

标签 sql database database-design normalization

这一直困扰着我一段时间,考虑一个具有如下属性的表:{ID, Value, Australia, India, France, Germany} , 其中 ID是主键,Value是一些文本,比如汽车型号,在每个属性下,如 Australia , India是与该值相对应的汽车制造数量。

直觉上我知道 {ID, Value, Cars-Manufactured, Country} 的正确表达方式,但有人能告诉我为什么这在数据库规范化方面是正确的吗?第一个表不符合哪个规范化。还是第一张表也正确?

最佳答案

它违反的规则是“没有重复组”。这是第一范式的规则之一。

每个国家的一列是一个重复组。每列下的数据是相同的数据,只是适用于不同的上下文。当那里只有一个值(value)时——比如那个国家制造的汽车数量——这可能并不明显,甚至可能值得商榷。但是假设我们需要每个国家/地区的两条信息,例如制造数量和销售数量。现在该表有一组成对的列:Australia_manufactured、Australia_sold、India_manufactured、India_sold、France_manufactured、France_sold 等。您有一组重复多次的两列。

有人可能会问,多个不同的字段和重复组有什么区别? “India_manufactured, Australia_manufactured, France_manufactured”与“number_manufactured, price, description”有何不同?不同的是,在第一种情况下,值的语义是相同的,不同的是一个上下文,一个应用程序。第二种情况,语义不同。也就是说,很难想象一个查询或程序会处理超出微不足道的“找到最大值”的数据,或者我们今天将运行它处理 number_manufactured,然后在明天运行它执行完全相同的处理但在销售价格。但我们可以很容易地想象今天为印度竞选,明天为德国竞选。

当然,有时它可能是模棱两可的。这就是为什么数据库设计人员获得大笔报酬的原因。 :-)

好吧,这就是规则。规则有实用值(value)吗?

让我们考虑场景 A,一张表:

model (model_id, description, india_manufactured, australia_manufactured, france_manufactured)

场景B,两张表:
model (model_id, description)
production (model_id, country_code, manufactured)

场景 A 糟糕的原因有很多。这是最大的:

使用场景 B,查询要简单得多。我们不必将国家/地区硬编码到我们的程序或查询中。编写查询以接受国家代码作为参数并返回在该国家制造的每种型号的数量。在场景 B 中,简单:
select description, manufactured 
from model join production on model.model_id=production.model_id
where production.country_code=@country

简单。现在用场景 A 来做。像:
select description,
  case when @country_code='IN' then india_manufactured
  when @country_code='AU' then australia_manufactured
  when @country_code='FR' then france_manufactured
  else null
  end as manufactured
from model

或者假设我们想要所有国家的总产量。场景 B:
select description, sum(manufactured)
from model
join production on model.model_id=production.model_id

情景一:
select description, india_manufactured+australia_manufactured+france_manufactured
from model

(如果我们必须允许空值,可能会更复杂。)

在整个系统中,我们可能会有很多很多这样的查询。在现实生活中,许多会比这复杂得多,有多个这样凌乱的 case 子句或杂耍多个列。现在假设我们添加另一个国家。在场景 B 中,这是零努力。我们可以添加和删除我们喜欢的所有国家,并且查询不会改变。但在场景 A 中,我们必须找到每个查询并更改它。如果我们错过了一个,我们将不会得到任何编译错误或类似的东西。我们只会神秘地得到不正确的结果。

哦,顺便说一句,有时我们可能只想处理某些国家/地区。比如说,有些国家有增值税,有些没有,或者其他什么。在场景 B 中,我们为此事实添加一列并对其进行测试。这只是“在 country.country_code=production.country_code 和 country.vat=1 上加入国家”。在场景 A 中,程序员几乎肯定会在每个查询中硬编码特定国家的列表。后来有人过来,看到查询 X 处理印度和法国,查询 Y 处理法国和德国,查询 Z 处理德国和新加坡,他可能不知道为什么。即使他知道,该列表在每个查询中都是硬编码的,因此每次更新都需要更新每个查询,更改代码而不是更改数据。

假设我们遇到一个只处理四个国家中的三个的查询。

哦,顺便说一句,

我们怎么知道这是否是一个错误,有人在编写查询时忘记了其中一个国家,或者在添加新国家时错过了这个查询;或者这个国家被排除在外有什么原因吗?

关于sql - 以国家为列的数据库中的规范化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14087988/

相关文章:

sql - PostgreSQL : Building a nested json structure on a single table?

mysql - 尝试编写一个查询来计算具有不同情况的多个事物

android - 在android中创建存储图像的数据库

database - 将图像存储在数据库中并使用 nhibernate 映射它们

mysql - 音乐库 MySQL 数据库

html - 在 SQL Server 中存储 HTML

sql - RoundFunctionSQL 最多到最接近的 10

java - java中执行多条SQL语句

asp.net - 哪个最快?数据检索

python - bool 标志字段的模式设计(数据库架构)