数据库设计:递归多对多关系

时间:2010-09-15 21:09:07

标签: database

我有n个以多对多方式相关的表格。我想知道如何在不为每个关系创建中间表的情况下表示这样的模型,因为这会导致一些大量的表。为此,假设n足够大,不想创建表。

例如,我可能有三个表,其中n是3:

Parking_Lot
Car
Person

一辆汽车可停放在许多停车场,停车场将停放许多汽车。 一个人可以开很多车,一辆车可以有很多车手。 停车场有很多人,许多人可以在停车场。 (人们可能是雇员,或者他们可能只是在停车场。请不要过分分析这个例子,因为这只是一个例子。)

要对此进行建模,您将拥有3个表(Lot, Car, Person)和三个关系表。

假设您添加了第4张食物。许多停车场,许多汽车和许多人都可以食用食物。这需要4个表+ 6 = 10个表。

如何在不创建大量中间表的情况下建模这种关系?

我对这个概念更感兴趣,但我主要使用c#所以如果有一个整洁的可能在.net中实现这一点我很满意。

8 个答案:

答案 0 :(得分: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)
);

然后所有其他实体从Node继承“

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

当然,如果您想在层次结构中找到更深层次的内容,则需要专门查询每个级别。但是因为你的实体(假设)是真实的东西,而不仅仅是层次结构中的层次,那应该没问题。)。

答案 1 :(得分:1)

像往常一样,“它取决于” -

这取决于您将如何处理信息

在规范化表示中,映射表是区分(可能是数据丰富的)关系的必要条件

在知识库表示中,单个类型的关系表就足够了,但它要求您将源和目标ID取消引用到不同的表

答案 2 :(得分:0)

你可以在其中创建一个带有类型id /表名的关系表。

relationship
      relationship_type_parent
      relationship_id_parent
      relationship_type_child
      relationship_id_child 

答案 3 :(得分:0)

您可以尝试使用中央关系表,每个实体表都有一列(允许NULL)。对于每个组合,都有一行包含有问题的ID。

这很棘手,但也可以让你对多路关系进行建模 - 例如人在停车场C驾驶汽车B.你可能想要添加某种标签,例如区分“停车场C中驾驶汽车B的人”和“停在C地停放汽车B的人A”。

答案 4 :(得分:0)

人们通常将系统与数据库(尤其是正确的建模)相关联,包括ACID持久性,这不是一个小功能。另一方面.net是应用程序的框架,与persistancee没有多大关系(它可以使用不同的后端来持久化)。因此,如果您不确定是否需要完整的RDBMS,或者您想要在内存结构中讨论,那么您的问题(一开始就很棘手)实际上没有答案。

否则,显式建模n加上所有二元关系表被认为是一个加号。

另外,你提到n +关系表,好像那是某种通用模型。但是,这不会处理三元或更高阶的关系,也不会处理多个二元关系(也不是多个高阶关系)。

我相信有人会提供EAV模型或某些扩展程序。

问题在于,通过这种方法,您可以获得灵活性,但却无法实际实现关系。

这一切都取决于为什么以及你需要这种持久性。

您可以创建某种混合 - 例如,根据描述您的关系的中心表自动创建表。如果你想要一个数据库。关系数据库。

您也可以使用XML或某些对象关系映射收费等进行类似的操作......

您需要更好地定义问题。

答案 5 :(得分:0)

正如其他人所说,这个答案完全取决于你正在做什么以及你为什么这样做。

数据库非常适合撤回数据的SETS以及对数据进行分类和汇总。这就是他们设计的(在许多其他事情中)。

它们在描述各个值之间的复杂关系(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)

在节点(边缘)之间创建关系只需要向EDGE表添加一个值。

遍历结构需要一组递归查询,查找当前节点的所有可能步骤,然后选择一个进入下一个节点。这对于RDBMS来说可能非常密集。

EG //

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

在你想去的路径上泡沫,冲洗并重复(这假设权重是成本而不是效益指标,图表是有向图)。

答案 6 :(得分:0)

我建议你需要少于10张桌子。考虑一个人吃食物X.如果人A位于停车场B,则食物X在同一停车场B吃;因此,您可能不需要有关食品和停车场的表格。

答案 7 :(得分:0)

呃,我想如果您使用具有一对多关系的“ category”表,则无论n有多高,您都只需要四个表。

表1 =您将人员,汽车,停车场,食物全部放入一张桌子的“事物”,并根据需要添加任意列

表2 =“事物关系”,在这里您可以将一个人与汽车,一个人与停车场,一个食物与汽车等相匹配....

表3 =“类别”,即人,停车场,汽车,食物

表4 =“类别关系”,您可以为每件事定义一个类别

也许我错了idk,但是如果您不希望表的数量成倍增加,这似乎是最好的解决方案

相关问题