2011-05-16 34 views
1

圓形relationshp我面臨這個問題:一到多,親子表中的MySQL

我有一個父表和子表,一個家長可以有多個孩子,標準的故事。

這些都是制約因素:

  • 每個家長必須有至少一個孩子,
  • 每個家長必須有一個最喜歡的孩子,
  • 每個家長可以有一個最低-favourite小孩

如何設計這在SQL中?

我不知道標準的親子表可以因循環關係中使用:

Parent table: 
parentId 
favouriteChildId NOT NULL 
leastFavouriteChildId NULL 

Child table: 
childId 
parentId 

我想使用橋接表的,但我不知道如何將這些約束模型。


編輯:只是爲了增加一些透明度,這裏的問題是環境的一部分:

有價格表(孩子),以及PriceGroup表(母公司)。

PriceGroup有多個價格,一個強制mainPrice(favouriteChild)並且可以有一個officialPrice(leastFavouriteChild)。

以下是無關的問題,但帶來了曙光上下文: 價格按他們指產品分組,一個產品可以有多個價格 - 這些都是然後在價格組分組,每個團隊需要參考主要價格和官方價格(如果有的話)。

+0

它只是父母和他們的直系後裔,還是可以是多層次的? **編輯**順便說一句:你不能'約束'(強迫)父母有一個孩子。 **編輯**數據庫關係被高估。您應該在模型中修復這些關係,這比所有這些MySQL鏈接都重要得多。 – Rudie 2011-05-16 10:02:58

+0

您將遇到問題,因爲您無法插入沒有parentId的子項,並且無法插入沒有childId的父項(在favouriteChildId中引用)。爲了能夠插入任何所需的內容(暫時)禁用外鍵約束,插入兩行,然後再次啓用外鍵約束,然後提交插入。我會盡量設計不同的表格。如果我們對問題定義有更好的理解,這可能會有所幫助。 – PatrikAkerstrand 2011-05-16 10:08:56

+2

我擔心有人會說「(暫時)禁用外鍵約束」。請不要這樣做,並重新考慮你的db模型。 – Rudie 2011-05-16 10:09:58

回答

3

出於你給

  1. 每位家長必須至少有一個孩子的業務規則,
  2. 每個家長都必須有一個最喜歡的孩子,
  3. 每個家長可以有一個最不喜歡的孩子

你的

Parent table: 
parentId (PK) 
favouriteChildId NOT NULL (FK) 
leastFavouriteChildId NULL (FK) 

Child table: 
childId (PK) 
parentId (FK) 
解決方案0

滿足2和3. 但它也滿足1(因爲favouriteChildId NOT NULL不允許創建沒有子項的父記錄)。

既然你已經有了上面的內容,我會假設真正的問題是你如何在Child table中創建parentId NOT NULL。

通常情況下,有規定在SQL這樣你可以做類似

BEGIN TRANS 
INSERT INTO TABLE1 (FK not checked yet) 
INSERT INTO TABLE2 (FK not checked yet) 
COMMIT (All integrity checked) 

在這種情況下,「循環引用」將不會是一個問題(見DEFERRED

MySQL不支持,讓你有以下選項

觸發器:
可以設想,在插入父記錄一個時最喜歡的孩子已經知道,那麼你可以將插入之前,對父表運行,並

  • 插入寵兒到子表中獲取其ID
  • 與孩子的ID插入父記錄觸發

注意:問題是這樣你可以正式滿足標準,但是首先要插入子記錄,你必須在父項中使用額外的列,以便觸發器可以知道子表中的其他字段或插入空白記錄(在任何一種情況下,設計都不乾淨)

完整性通過安全
以上可以實現爲存儲過程而不需要在父表級別上的附加字段。但是,通常可以繞過存儲過程,因此它不符合真正的完整性規則。

有一種通用的方法可以使通過存儲過程實現的某些東西成爲完整性規則 - 即刪除這些表的所有常規用戶(和應用程序)的寫入權限,並允許僅通過存儲過程。

編輯: 關於觸發器,還有一種方法來實現帶觸發器的規則,也就是接受你將不得不單獨插入記錄,並且你必須有一段時間必須有破壞業務規則的數據。

在這種情況下,您可以爲父記錄創建一個STATUS atrribute(例如:COMPLETE vs INCOMPLETE)並將favouriteChildId設爲可空的FK,但當狀態更新爲COMPLETE時,可以觸發檢查是否遵守完整性。

這需要額外的列,但可以使事情挺乾淨的(實際上就可以創建這個表,只會暴露僅是完整的記錄一看,這實際上使得看起來像FK NOT NULL表)。

0

如果只有一個級別深度:

Parents (ParentID, Title, etc) 
Children (ChildID, ParentID, Title, etc) 

每個Child必須始終有恰好1 ParentParents總是有>= 0 Children。 (有周圍沒辦法。)

如果多個(未知)級深:

Items (ItemID, ParentItemID NULL, Title, etc) 

很簡單:Items.ParentItemID = Items.ItemID

編輯
如果需要幾種(未知)層次深,查詢將是多個並緩存總結果將是一個非常非常好的主意。 (每個孩子都會有另一個查詢來獲取它的直接孩子等等。)

+0

這是一個基本的一對多表模型,因此沒有多層次的層次結構。 – 2011-05-16 10:47:18

2

您還可以模擬(在一定程度上)其他約束:

Parent Table 
parentId (PK) 

Child table: 
childId (PK) 
parentId (FK) 

Is Favorite table: 
childID (PK)(FK) 

Is Least Favourite table: 
ChildID (PK)(FK) 

一行將始終被插入到被寵愛的孩子;只有在最不喜歡的孩子時纔會插入「最不常用」:插入,更新,刪除由視圖上的觸發器完成;通過表上的左連接進行選擇。

這並不涉及Favorite Child關係的強制性質 - 這必須通過insert/update/delete觸發器來處理。