在数据库列中自然“适合”时对数据进行编码

时间:2013-05-29 21:47:39

标签: database normalization

我的任务是规范化一些数据库数据。 99%的情况很好,但我已经打了一个quardry。

它不是我的问题领域,但类似的是书籍。想象一下,您必须记录书籍的详细信息,以及它们如何在供应商网站上展示(可能是价格比较引擎)

供应商A,B和C的每本书都由一个数字标识符表示(虽然每个供应商都不同)但是,供应商D每年的发布时间为1,因此您还需要发布年份。

如果我只需要处理A,B和C,我就会有一个主表书,以及一个将我的主书ID映射到供应商特定ID的查找表。但供应商D打破了这一点。例如,我不能使vendorID,vendorCode成为唯一的密钥,因为对于D,供应商代码可以重复使用(代码1每年将有不同的条目....)

一个答案是让D的供应商代码成为一个组合变量 - 所以“123,2013”​​代表id 123,年份= 2013,并且在我的查找代码中有类似的内容:

if(vendor = D){
...split the code in two and format the search request accordingly...
}

但似乎有点......哈基。

我是否错过了DB规范化的一些微妙技巧?或者我只是需要接受现实世界并不总是以一种很好的方式正常化?

1 个答案:

答案 0 :(得分:0)

您的场景类似于数据仓库和旧系统中常见的场景:映射来自多个系统的主键。光谱的两端看起来像这样。 (很明显,供应商D的真实密钥必须包括年份。)

One end of the spectrum
our_key  vendor_a  vendor_b  vendor_c  vendor_d_yr  vendor_d_num
--
1001     32        43        1856      2013         1
1002     143       887       2924      2013         2

那种表(到目前为止)有五个候选键。

  • our_key
  • vendor_a
  • vendor_b
  • vendor_c
  • vendor_d_yr,vendor_d_num

如果您的dbms支持复合的,用户定义的类型,则可以使用供应商“D”的复合类型。

The other end of the spectrum
our_key  vendor  vendor_key
--
1001     A       32        
1001     B       43
1001     C       1856
1001     D       2013-1
1002     A       143
1002     B       887
1002     C       2924
1002     D       2013-2

此表有一个候选键:{our_key,vendor,vendor_key}。频谱的这一端基本上是EAV结构。

做出选择

如果实用,我更喜欢第一种结构。它允许高级别的约束检查。每列可以(通常是)不同的数据类型,列级约束易于应用和理解。您不必将shoehorn复合类型放入单个列中,也不必在SELECT语句中解析该列。

但是,如果必须支持不确定数量的供应商,那么这是不切实际的。每个dbms都对您可以在基表中声明的列数有硬限制或软限制。

但是EAV结构有一些缺点,可能是显示停止,取决于您的应用程序。例如,保证“our_key”的每个值都映射到第一个结构中每个供应商的密钥都是微不足道的。在EAV结构中几乎不可能做到这一点。

EAV还要求您将复合类型解压缩到一个列中,并在SELECT语句中解析该列。