2010-09-15 162 views
2

我有n在多對多的基礎上相關的表的數量。我想知道如何在不爲每個關係創建中間表的情況下表示這樣的模型,因爲這會導致大量表格。爲此目的假設n足夠大,不想創建表。數據庫設計:遞歸多對多關係

比如我可能有三個表,其中n爲3:

Parking_Lot 
Car 
Person 

一輛車可以在許多停車場停放和停車場將有很多汽車。 一個人可能駕駛很多汽車,而一輛汽車可能有很多駕駛員。 一個停車場有很多人,許多人可以在停車場。 (這些人可能是員工,或者他們可能只是身在停車場,請不要過分分析這個例子,因爲它只是一個例子。)

要模擬這個,你將有3個表格(Lot, Car, Person)和三個關係表。

假設你添加第四張食物表。食物可以在許多停車場,許多汽車和許多人中吃掉。這需要4張桌子+6 = 10張桌子。

如何在不創建大量中間表的情況下模擬這種關係?

我對這個概念更感興趣,但我主要使用c#,所以如果有一個整潔的可能在.net中完成這個我都是耳朵。

回答

0

你可以創建一個類型爲id /表名的關係表。

relationship 
     relationship_type_parent 
     relationship_id_parent 
     relationship_type_child 
     relationship_id_child 
+0

relationship_type =「Parking_lot」,「Car」,「Person」 – 2010-09-15 21:21:01

0

你可以嘗試建立一箇中心關係表,每個實體表有一列(允許爲NULL)。對於每個組合,請使用有問題的ID。

這會變得棘手,但也可以讓您爲多路關係建模 - 例如,人在停車場C中駕駛汽車B.您可能還想添加某種標籤,例如區分「停車場C中的人A駕駛汽車B」和「人A擁有停在C組中的汽車B」。

+0

所以一個表格應該有{LotID,CarID,PersonID,FoodID}列,我可以根據需要填寫它們。這是有道理的,有沒有關於這種方法的相關着作的任何文件? – joe 2010-09-15 21:47:24

+0

我讀到的最接近的東西就是數據倉庫的「明星」模式,儘管這不完全是這樣。話雖如此,你也許可以將你的問題映射到一個更適合的「明星」模式(或者是相關的「雪花」)。見例如http://en.wikipedia.org/wiki/Star_schema – jsegal 2010-09-15 23:59:25

1

像往常一樣,「這取決於」 -

這取決於你打算用什麼樣的信息

做的標準化表示映射表是必要的區分(大概是數據豐富)在知識庫表示一個類型化的關係表就足夠了,但它需要你解引用源和目的地編號不同的表

+0

同意。它可能是很多映射表,但他們出於某種原因。 – 2010-09-15 21:46:52

0

P相互

關係人們通常將系統與數據庫相關聯(尤其是正確的建模),包括ACID持久性,這不是一個小功能。另一方面,.net是一個應用程序框架,與持久性沒有多大關係(它可以使用不同的後端來實現持久性)。因此,如果您不確定是否需要完整的RDBMS,或者您想要在內存結構中進行討論,那麼您的問題(最初很棘手)實際上沒有答案。

否則,顯式建模n加上所有的二元關係表被認爲是一個加號。

另外,你提到n加關係表,就好像這是一種通用模型。但是,這不涉及三元或更高階的關係,也不關心多個二元關係(也不涉及多個更高階的關係)。

我相信有人會提供EAV模型或一些擴展它。

問題是,用這種方法你會獲得靈活性,但卻喪失了真正實現關係的能力。

這一切都取決於爲什麼,以及你需要這種堅持。

您可能會創建某種混合 - 例如基於某些描述您關係的中心表自動創建表。如果你想要一個數據庫。關係型數據庫。

你可以做類似的事情也與XML或一些對象關係映射過路費,等...

您需要更好地界定問題。

+0

這更多的是我在思考的理論問題,但是我在關係數據庫中只考慮了基本的二元關係。 – joe 2010-09-15 21:46:04

+0

@joe,爲什麼只有二進制?你究竟想要建模什麼?你想要捕捉和查詢什麼樣的事實? – Unreason 2010-09-16 09:10:00

0

正如其他人所說,這個答案完全取決於你在做什麼,爲什麼你這樣做。

數據庫非常適合於取回數據集以及對數據進行分類和彙總。這就是他們設計的(其他許多事情)。

他們不能很好地描述個人價值觀之間的複雜關係(x深n:m關係)。來自NoSQL運動的隨機訪問結構在這方面更好。

如果您真的想要使用經典的RDBMS,可以使用邊和節點的概念將問題建模爲數據庫中的圖形。節點具有0:N邊和0:N屬性/值(如上所述的EAV)。邊緣有2個節點,可能還有一個重量。

可以用它進行建模:

NODE ([node_id, entity, attribute], value) 
EDGE ([src_node_id, dest_node_id], weight) 

創建節點之間(的邊緣)之間的關係需要簡單地增加一個值到邊緣表。

遍歷結構需要一個遞歸的查詢集,查找當前節點的所有可能步驟,然後選擇一個到達下一個節點。對於RDBMS來說,這可能會很緊張。

EG //

SELECT dest_node_id 
FROM EDGE 
WHERE src_node_id = <<This Node ID>> 
ORDER BY weight ASC 
LIMIT 1 

泡沫,沖洗和重複的但遠了你想要去的路徑(假定重量是一種成本,而不是度量的利益,該圖是一個有向圖)。

0

我建議你需要少於10個表格。考慮一個人食用食物X.如果人A位於停車場B上,則食物X在同一停車場B上吃飯;因此你不可能需要一張關於食物和停車場的表格。

3

我想通過使用幾乎多態的方法來解決這個問題。你可以只用兩個表,就像這樣:

CREATE TABLE Node (id UNIQUEIDENTIFIER NOT NULL, PRIMARY KEY (id)); 
CREATE TABLE Relationships (
    parent UNIQUENIDENTIFIER NOT NULL, 
    child UNIQUEIDENTIFIER NOT NULL, 
    CONSTRAINT FK_Relationship_ParentNode 
     FOREIGN KEY (parent) REFERENCES Node(id), 
    CONSTRAINT FK_Relationship_ChildNode 
     FOREIGN KEY (child) REFERENCES Node(id) 
); 

那麼所有其他實體節點「繼承」:

CREATE TABLE Person (
    id UNIQUEIDENTIFIER NOT NULL, 
    name NVARCHAR(50) NOT NULL, 
    CONSTRAINT FK_Person_Node 
     FOREIGN KEY (id) REFERENCES Node(id) 
); 

CREATE TABLE ParkingLot (
    id UNIQUEIDENTIFIER NOT NULL, 
    name NVARCHAR(50) NOT NULL, 
    address NVARCHAR(250) NOT NULL, -- bad way to model 
    CONSTRAINT FK_ParkingLot_Node 
     FOREIGN KEY (id) REFERENCES Node(id) 
); 

CREATE TABLE Food (
    id UNIQUEIDENTIFIER NOT NULL, 
    name NVARCHAR(50) NOT NULL, 
    calories INT NOT NULL, -- hopefully only needs an int ;) 
    CONSTRAINT FK_Food_Node 
     FOREIGN KEY (id) REFERENCES Node(id) 
); 

所以現在你可以模擬任何兩個實體之間的關係,並找一找使用連接。

例如,如果你想找到哪些食物屬於哪個人,你可以說:

SELECT p.name AS person, f.name AS food 
FROM Person AS p 
INNER JOIN Relationships AS r 
ON r.parent = p.id 
INNER JOIN Food AS f 
ON f.id = r.child 

當然,如果你再想要找到的東西在層次更深一點,你需要專門查詢每個級別。但是,因爲你的實體(假定)是真實的東西,而不僅僅是層次結構中的層次,所以應該沒問題:)。