2014-08-27 23 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