2010-09-15 142 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 

当然,如果你再想要找到的东西在层次更深一点,你需要专门查询每个级别。但是,因为你的实体(假定)是真实的东西,而不仅仅是层次结构中的层次,所以应该没问题:)。