2014-08-27 51 views
0

我有一个名为Users的表,它有一个不断增长的首选项列表。这些偏好可以包括ReligionId(这将关键到另一个包含宗教列表的表)。用户表和用户首选项。这是正常化的吗?

偏好列表正在增加。我想将它从Users表中拆分成2个表格。我认为最好的策略是制作一个名为UserPreferences的单独表格。我想知道这样做是否符合正常化规则。这是一个让事情变得更清晰的例子。

enter image description here

这是标准化?有更好的方法吗?所有评论赞赏。

编辑:如何使用UserPreferences键切换到其他表:

enter image description here

+1

我不会在同一个表中存储SomePreference,AnotherPreference和另一个。这看起来像一张偏好表,应该对其进行标准化,以便每个偏好都在自己的行上。我建议将电子邮件和备用电子邮件移动到另一个表中。这样你就可以拥有尽可能多的电子邮件。另外,我会建议存储生日,而不是年龄。您可以根据静态出生日期计算年龄。如果你存储年龄,价值永远是陈旧的。 – 2014-08-27 20:49:16

+0

@SeanLange你会建议什么类型的表设置,以便每个首选项都在自己的行上? PrefId,Pref,PrefValue?我同意你的其余评论,这不是我的数据实际存储的方式,这只是为了解决这个问题。我确实存储了生日,并且只有一个电子邮件地址。虽然伟大的评论。 – user3308043 2014-08-27 20:52:24

+0

你很迷惑“正常化”与“精心设计”。 1NF意味着使用关系。你还没有给出非关系设计,所以你没有对1NF进行任何标准化。进一步向更高级的NFs“正常化”是用一个更小的投影来替代一个表,并将它加入它。这不是你的问题。所以问题是设计的质量。但是您的原始设计和EAV设计都是“糟糕的设计”,因为它们的用户规则(“谓词”)表示行是否在表中或者查询结果以及DBMS规则(“约束条件”)是否是有效的,这些都是不必要的复杂。 – philipxy 2014-08-27 22:28:23

回答

1

你至少可以只是用户和首选项。用户和偏好之间应该有一对多的关系。一个用户可以有许多偏好。您也可以将电子邮件地址分成另一个表格 - 这样一个用户可以有多个电子邮件地址 - 您可以有一个标志来表示主要电子邮件地址。该DDL看起来像:

create table Users 
    (
     UserId int, 
     Age int 
    ) 

    create table Preferences 
    (
     PreferencesId int, 
     UserId int, 
     ReligionId int, 
     PersonalDescription varchar(2000), 
     HairColor int 
    ) 

    create table EmailAddresses 
    (
     EmailId int, 
     UserId int, 
     EmailAddress varchar(100), 
     IsPrimary bit 
    ) 

    create table Religion 
    (
     ReligionId int, 
     Name varchar(200) 
    ) 

Insert into Religion (ReligionId, Name) Values (1, 'Jediism') 
Insert into Religion (ReligionId, Name) Values (2, 'Sithism') 
Insert into Religion (ReligionId, Name) Values (3, 'Yuuzhan Vong') 
Insert into Religion (ReligionId, Name) Values (4, 'Pinacism') 

Insert into Users (UserId, Age) Values (1, 30) 
Insert into Users (UserId, Age) Values (2, 18) 

Insert into Preferences (PreferencesId, UserId, ReligionId, PersonalDescription) values (1, 1, 1, 'a description') 
Insert into Preferences (PreferencesId, UserId, ReligionId, PersonalDescription) values (2, 1, 4, 'another description') 
Insert into Preferences (PreferencesId, UserId, ReligionId, PersonalDescription) values (3, 1, 4, 'even another description') 

Email table omitted

+0

好的,我在SQL中运行查询,看起来不错。一个问题:只能删除Preferences表中的PreferenceId?重点是什么? – user3308043 2014-08-27 21:58:14

+0

有一个主键来识别行是非常重要的。这应该是独一无二的。如果你没有这个,你有两个相同的行,你想删除一个 - 这将是非常困难的没有一个独特的主键。 – Donal 2014-08-27 22:09:20

+0

是的,当然,这是DBMS系统的基本支柱之一。但是,每行只能在Preferences表中用UserId唯一标识。但是,在整个数据库中,是的,它将结合使用UserId + PrefernceId来唯一标识这些记录。 – user3308043 2014-08-27 22:11:23

1

它没有意义在拆分单个表两张表。只有你这样分裂的时间是某些用户根本没有首选项

创建一个新列 - 无论何时新首选项出现 - 不是一个好主意。

如果你认为将在未来的增长,你可以用下面的方法 -

enter image description here

+1

偏好值如何? – Beth 2014-08-27 20:54:37

+0

正是我想说的 – user3308043 2014-08-27 20:54:52

+1

我更新了答案。 – Win 2014-08-27 21:05:38

1

规范化userPreference表将包含用户ID,preferenceID和preferenceValue。偏好设置会将您的所有偏好设置(电子邮件,年龄等)列在一行中,ID为ID,以及您希望添加的任何描述性信息。


因为数据类型的偏好值的不同,你可以声明它作为一个字符串/ VARCHAR,或者,如果你真的想,有不同的数据类型的不同偏好值,如“prefValInt,”' prefValChar“等,其中只有一列包含一个值。

我通常只使用一个字符串。现在


,如果要强制引用完整性,就像在你上面的例子,你又回到了其在不同列中的每个preferenceID,所以你可能会希望让那些喜好在主表和所有查找表中的其他人。


需要RI执行,如religionID和hairColorID任何列,可以去在用户表中,或者可以在userPreferenceRI表去与用户表1-1关系。任何没有强制执行RI的列(例如age,dateOfBirth,accountBalance,emailBody)都可以进入userPreference表,其中PK是用户ID和preferenceID以及与用户表的一对多关系。

HTH


,你也应该考虑到现有的首选项的可能性。对于必需的字段,例如ageAtPointInTime或dateOfBirth,您应该将它们存储在用户表中。对于人口稀少的偏好(大多数人没有答案),你应该把它们放在查找表中。

user: userID, requiredFld1, requiredFld2 
    preference: preferenceID, preferenceName, preferenceDescription 
    userPreference: userID, preferenceID, userPreferenceVal as varchar(100) 
(list of columns never changes) 
    userPreferenceRelated: userID, religionID, hairColorID, otherPreferenceID 
(list of columns grows over time) 
+0

这是preferenceValue列,这是有问题的。它只能是一种数据类型和一种数据类型。 – user3308043 2014-08-27 21:01:26

+0

我知道你通常只是使用字符串,但是这不符合具有能够具有不同数据类型的数据库的目的。 – user3308043 2014-08-27 21:10:05

+0

我的意思是,你必须有参照完整性。这就是DBMS系统存在的原因。这就是PK/FK存在的原因。整个问题是主桌的大小不断膨胀。 – user3308043 2014-08-27 21:15:05

1

如果你说你有成长的偏好,那么我会建议你做的偏好的新表和的Fkey添加到使用UserPreferences

表的用户 - 用户ID,电子邮件,年龄,ALTERNATEEMAIL ...

偏好表 - Preferenceid,preference_Value,活性,需要

用户偏好表 - 用户标识,preferenceid,preference_data

现在,您可以在首选项表中将不断增加的首选项列表连接到用户界面,并且这两列(活动的和必需的)将帮助您从后端轻松控制表单。

而在用户偏好表中,您只需使用用户标识引用偏好ID,并存储用户为该偏好输入的数据。

我希望这很清楚。

+0

大部分是,但是preference_value存储和preference_data存储什么? – user3308043 2014-08-27 20:58:57

+0

优先值包含首选项的名称。在你的表格中,你有 - “关系状态”,所以这是一个preference_value。而preference_data是这个首选项的用户输入,例如 - “Single”。 对不起,关于命名约定。 – hangvirus 2014-08-27 21:12:40

+0

这是EAV风格。你正在抛出你使用关系数据库的所有原因。请参阅比尔卡尔文的回答。 – user3308043 2014-08-27 22:43:33

3

一些人建议存储偏好每行一个。这称为实体 - 属性 - 值表,并且它是而不是归一化的。有人说EAV是“更规范化”,但他们错了。没有规范化的规则鼓励EAV作为关系数据库中的设计。你可以告诉它

一个切实可行的办法不是标准化的是,你可以不再使用外键约束你的宗教查找表,如果所有喜好的所有值在这个喜好表共享一个列。您不能使外键约束仅限于特定首选项类型的行上的值--FK约束始终适用于表中的所有行。
基本上,实体属性值打破了SQL对约束的支持。

唯一标准化设计是定义一个单独的列为每个不同的偏好。然后,您可以定义适合该首选项类型的数据类型和约束条件。

如果你真的想了解关系和规范化,阅读SQL and Relational Theory: How to Write Accurate SQL Code by C. J. Date

每一列代表从一组选项。一组可以是一组整数,或一组宗教或一组电子邮件地址。表格中的一行是一组“配对”的集合,例如给定的用户具有姓名,出生日期,宗教信仰和电子邮件地址,因此这些值被一起匹配成一行,并且他们一起描述了世界上存在的东西,即具有这些属性的人类。

这意味着,在每一行中,您为每个列选择一个值,即从每个引用的组件集中选择一个值。并且每列包含来自一组的值只有。在宗教专栏中,您只能选择宗教,您也不能将喜欢的颜色和母亲的婚前姓名和鞋号放在同一列。

这就是为什么EAV从关系角度来看是虚假的,因为它将来自任何和所有不同属性的值糅合到同一列中。它更像是电子表格而不是数据库。我并不是说关系数据是存储数据的唯一方法。只是,如果您问EAV是否归一化,并且规范化假定数据是关系型的先决条件,那么否,EAV不是关系型的,因此不能归一化。

+0

感谢您花时间回答我的问题,我完全同意您的观点。我试图远离EAV和序列化。我有一个数据库管理系统,我想我应该以它的使用方式来使用系统的功能。但是,在这种情况下,我遇到的用户表变得太宽了。简单地将这张表分成与标准化规则一致或者可能是非规范化的可接受形式?也许只是一个UserPreferences表,其中包含UserId的单个主键,其中包含所有这些附加数据?你怎么看? – user3308043 2014-08-27 21:42:36

+1

有时,非关系型解决方案是一种更实用的数据存储方式,即使SQL不支持某些功能。您可能会喜欢我的演示[可扩展数据建模](http://www.slideshare.net/billkarwin/extensible-data-modeling)。 – 2014-08-27 21:57:29

+1

是的,它开始看起来像那样。很棒的介绍。所以这真的是一个需要衡量和平衡优势和劣势的场景。 – user3308043 2014-08-27 22:08:38